Repository: melt-ui/melt-ui
Pull request #1053 (2024-03-04 14:10:38)

[link preview] fix content showing up at top left after remounting trigger
closes https://github.com/melt-ui/melt-ui/issues/1060

setting `activeTrigger` in trigger action (when trigger is mounted) instead of in `safeOnMount`. This makes sure that we always have a reference to the up-to-date trigger every time a new trigger mounts. Currently, if you just unmount the trigger and remount it, we have a stale `activeTrigger` which breaks the behavior of the component as seen in the mentioned issue above

### Before

https://github.com/melt-ui/melt-ui/assets/53095479/c2dbc10c-314b-44a7-b91e-7330d74d66e5

### After

https://github.com/melt-ui/melt-ui/assets/53095479/2d571348-4695-4307-9735-927e17c3d923


changeset-bot[bot]: ###  ⚠️  No Changeset found

Latest commit: b3e774bcd1070c22f54f952bfdf77284115a16ed

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. **If these changes should result in a version bump, you need to add a changeset.**

<details><summary>This PR includes no changesets</summary>

  When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

</details>

[Click here to learn what changesets are, and how to add one](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md).

[Click here if you're a maintainer who wants to add a changeset to this PR](https://github.com/anatolzak/melt-ui/new/refactor/link-preview?filename=.changeset/mean-rockets-bake.md&value=---%0A%22%40melt-ui%2Fsvelte%22%3A%20patch%0A---%0A%0Arefactor%20link%20preview%0A)



Patch:
diff --git a/.changeset/dry-dolls-greet.md b/.changeset/dry-dolls-greet.md
new file mode 100644
index 00000000..89bb0c7c
--- /dev/null
+++ b/.changeset/dry-dolls-greet.md
@@ -0,0 +1,5 @@
+---
+'@melt-ui/svelte': patch
+---
+
+fix(link preview): Fixed bug where content shows up at top left of the page after remounting trigger (fixes #1060)
diff --git a/.changeset/khaki-files-try.md b/.changeset/khaki-files-try.md
new file mode 100644
index 00000000..39b1cd66
--- /dev/null
+++ b/.changeset/khaki-files-try.md
@@ -0,0 +1,5 @@
+---
+'@melt-ui/svelte': patch
+---
+
+Enhanced type accuracy by implementing as const for builder props, ensuring more precise type inference.
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
index 8a67c523..67262874 100644
--- a/.github/FUNDING.yml
+++ b/.github/FUNDING.yml
@@ -1,6 +1,6 @@
 # These are supported funding model platforms
 
-github: [tglide]
+github: [tglide, huntabyte]
 patreon: # Replace with a single Patreon username
 open_collective: # Replace with a single Open Collective username
 ko_fi: thomasglopes
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 8fc78646..a0488854 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -14,7 +14,7 @@ concurrency:
 
 permissions:
   contents: read # to fetch code (actions/checkout)
-  
+
 jobs:
   Lint:
     runs-on: ubuntu-latest
@@ -35,7 +35,6 @@ jobs:
           version: 8.6.3
           run_install: true
       - run: GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }} && pnpm run check
-      
 
   Tests:
     runs-on: ubuntu-latest
@@ -46,4 +45,16 @@ jobs:
           version: 8.6.3
           run_install: true
       - run: GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }} && pnpm run test
-      
\ No newline at end of file
+
+  Playwright-Tests:
+    name: Playwright Tests
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v3
+      - uses: pnpm/action-setup@v2
+        with:
+          version: 8.6.3
+          run_install: true
+      - name: Install Playwright Browsers
+        run: pnpm exec playwright install --with-deps
+      - run: GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }} && pnpm run pw
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3cdd6cb4..dfa35dc6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,53 @@
 # @melt-ui/svelte
 
+## 0.76.2
+
+### Patch Changes
+
+- Fixed a bug on touch devices where an outside interaction leaked click events to other dom elements (closes #1115) ([#1118](https://github.com/melt-ui/melt-ui/pull/1118))
+
+## 0.76.1
+
+### Patch Changes
+
+- Fixed bug where focus trap deactivates in dialog and popover when clicking outside provided `closeOnOutsideClick: false` (closes #1084) ([#1094](https://github.com/melt-ui/melt-ui/pull/1094))
+
+- Combobox: menu no longer closes when composing (Closes: #1106) ([#1107](https://github.com/melt-ui/melt-ui/pull/1107))
+
+- Fixed bug where focus trap deactivates in dialog and popover when pressing escape provided `closeOnEscape: false` (closes #1091) ([#1095](https://github.com/melt-ui/melt-ui/pull/1095))
+
+- Fixed memory leak caused by race conditions for various components (closes #1086) ([#1087](https://github.com/melt-ui/melt-ui/pull/1087))
+
+- performance: avoid effect multiple runs ([#1089](https://github.com/melt-ui/melt-ui/pull/1089))
+
+- Listbox: correct `arrowSize` JSDoc defaultValue ([#1050](https://github.com/melt-ui/melt-ui/pull/1050))
+
+- Popover: fixed a bug that has the potential to introduce a memory leak via the overlay ([#1112](https://github.com/melt-ui/melt-ui/pull/1112))
+
+## 0.76.0
+
+### Minor Changes
+
+- fix: datepicker not syncing with calendar + add defaults from calendar to datepicker ([#1076](https://github.com/melt-ui/melt-ui/pull/1076))
+
+### Patch Changes
+
+- Fix incorrect arrow position for Tooltip, Popover, Listbox, Link Preview provided forceVisible: false (closes #1048) ([#1049](https://github.com/melt-ui/melt-ui/pull/1049))
+
+- fix: months not updating when changing options ([#1070](https://github.com/melt-ui/melt-ui/pull/1070))
+
+- Floating: `data-side` & `data-align` for floating content ([#1082](https://github.com/melt-ui/melt-ui/pull/1082))
+
+- fix: months not updating when changing options (range calendar) ([#1072](https://github.com/melt-ui/melt-ui/pull/1072))
+
+## 0.75.3
+
+### Patch Changes
+
+- fix(Tooltip, Link Preview, Menu, Popover, Listbox) fixed bug where content jumps to top left of page during external unmounting when using out transition on the content and else if block to render the content (closes #1058, #1039) ([#1059](https://github.com/melt-ui/melt-ui/pull/1059))
+
+- Portalled Elements: fixed a bug where clicking inside a nested 'portalled' element would cause the parent to close ([#1066](https://github.com/melt-ui/melt-ui/pull/1066))
+
 ## 0.75.2
 
 ### Patch Changes
diff --git a/package.json b/package.json
index 21787e82..e79589bc 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "@melt-ui/svelte",
-	"version": "0.75.2",
+	"version": "0.76.2",
 	"license": "MIT",
 	"repository": "github:melt-ui/melt-ui",
 	"author": "Thomas G. Lopes",
diff --git a/playwright.config.ts b/playwright.config.ts
index 07994026..51ef844b 100644
--- a/playwright.config.ts
+++ b/playwright.config.ts
@@ -35,17 +35,17 @@ export default defineConfig({
 	projects: [
 		{
 			name: 'chromium',
-			use: { ...devices['Desktop Chrome'] },
+			use: { ...devices['Desktop Chrome'], hasTouch: true },
 		},
 
 		{
 			name: 'firefox',
-			use: { ...devices['Desktop Firefox'] },
+			use: { ...devices['Desktop Firefox'], hasTouch: true },
 		},
 
 		{
 			name: 'webkit',
-			use: { ...devices['Desktop Safari'] },
+			use: { ...devices['Desktop Safari'], hasTouch: true },
 		},
 
 		/* Test against mobile viewports. */
diff --git a/src/docs/components/nav/mobile-nav.svelte b/src/docs/components/nav/mobile-nav.svelte
index 8581a9e5..9698413a 100644
--- a/src/docs/components/nav/mobile-nav.svelte
+++ b/src/docs/components/nav/mobile-nav.svelte
@@ -25,8 +25,8 @@
 	<Menu class="size-6" />
 	<span class="sr-only">Toggle Menu</span>
 </button>
-<div use:melt={$portalled} class="md:hidden">
-	{#if $open}
+{#if $open}
+	<div use:melt={$portalled} class="md:hidden">
 		<div
 			use:melt={$overlay}
 			class="fixed inset-0 z-50 bg-black/80 backdrop-blur-sm"
@@ -86,8 +86,8 @@
 				</div>
 			</div>
 		</div>
-	{/if}
-</div>
+	</div>
+{/if}
 
 <style lang="postcss">
 	.menu,
diff --git a/src/docs/components/tooltip.svelte b/src/docs/components/tooltip.svelte
index e381cca6..29fc37d8 100644
--- a/src/docs/components/tooltip.svelte
+++ b/src/docs/components/tooltip.svelte
@@ -1,6 +1,6 @@
 <script lang="ts">
-	import { browser } from '$app/environment';
 	import { createTooltip, melt } from '$lib/index.js';
+	import { fade } from 'svelte/transition';
 
 	const {
 		elements: { trigger, content, arrow },
@@ -20,30 +20,20 @@
 	<slot />
 </div>
 
-<div
-	use:melt={$content}
-	class="z-50 rounded-md bg-neutral-700 px-2 py-1 text-sm text-neutral-50 shadow-sm"
-	data-open={$open ? '' : undefined}
-	class:hidden={!browser}
->
-	<div use:melt={$arrow} />
-	{text}
-</div>
+{#if $open}
+	<div
+		use:melt={$content}
+		in:fade={{ duration: 150 }}
+		class="z-50 rounded-md bg-neutral-700 px-2 py-1 text-sm text-neutral-50 shadow-sm"
+	>
+		<div use:melt={$arrow} />
+		{text}
+	</div>
+{/if}
 
 <style lang="postcss">
 	[data-melt-tooltip-trigger] {
 		display: grid;
 		place-items: center;
 	}
-
-	[data-melt-tooltip-content] {
-		opacity: 0;
-		visibility: hidden;
-		transition: opacity 150ms ease;
-
-		&[data-open] {
-			opacity: 1;
-			visibility: visible;
-		}
-	}
 </style>
diff --git a/src/docs/content/builders/dialog.md b/src/docs/content/builders/dialog.md
index 4e406287..a1d5e168 100644
--- a/src/docs/content/builders/dialog.md
+++ b/src/docs/content/builders/dialog.md
@@ -28,16 +28,16 @@ At a high level, the anatomy of a dialog looks like this:
 
 <button use:melt={$trigger}> Open Dialog </button>
 
-<div use:melt={$portalled}>
-	{#if $open}
+{#if $open}
+	<div use:melt={$portalled}>
 		<div use:melt={$overlay} />
 		<div use:melt={$content}>
 			<h2 use:melt={$title}>Dialog Title</h2>
 			<p use:melt={$description}>Dialog description</p>
 			<button use:melt={$close}> Close Dialog </button>
 		</div>
-	{/if}
-</div>
+	</div>
+{/if}
 ```
 
 - **Trigger**: The button(s) that open the dialog
diff --git a/src/docs/data/builders/combobox.ts b/src/docs/data/builders/combobox.ts
index 443b9fff..71c3b728 100644
--- a/src/docs/data/builders/combobox.ts
+++ b/src/docs/data/builders/combobox.ts
@@ -1,6 +1,6 @@
 import { ATTRS, KBD, PROPS, SEE } from '$docs/constants.js';
 import type { KeyboardSchema } from '$docs/types.js';
-import { builderSchema, elementSchema } from '$docs/utils/index.js';
+import { builderSchema, elementSchema, floatingSideAndAlignDataAttrs } from '$docs/utils/index.js';
 import { comboboxEvents } from '$lib/builders/combobox/events.js';
 import { listboxIdParts } from '$lib/builders/listbox/create.js';
 import type { BuilderData } from './index.js';
@@ -153,6 +153,7 @@ const builder = builderSchema(BUILDER_NAME, {
 const menu = elementSchema('menu', {
 	description: 'The combobox menu element',
 	dataAttributes: [
+		...floatingSideAndAlignDataAttrs,
 		{
 			name: 'data-melt-combobox-menu',
 			value: ATTRS.MELT('menu'),
diff --git a/src/docs/data/builders/link-preview.ts b/src/docs/data/builders/link-preview.ts
index e37da8ab..9fa6f412 100644
--- a/src/docs/data/builders/link-preview.ts
+++ b/src/docs/data/builders/link-preview.ts
@@ -1,5 +1,5 @@
 import { ATTRS, PROPS } from '$docs/constants.js';
-import { builderSchema, elementSchema } from '$docs/utils/index.js';
+import { builderSchema, elementSchema, floatingSideAndAlignDataAttrs } from '$docs/utils/index.js';
 import { linkPreviewIdParts } from '$lib/index.js';
 import { linkPreviewEvents } from '$lib/builders/link-preview/events.js';
 import type { BuilderData } from './index.js';
@@ -77,6 +77,7 @@ const trigger = elementSchema('trigger', {
 const content = elementSchema('content', {
 	description: 'The content displayed in the linkpreview',
 	dataAttributes: [
+		...floatingSideAndAlignDataAttrs,
 		{
 			name: 'data-state',
 			value: ATTRS.OPEN_CLOSED,
diff --git a/src/docs/data/builders/menu.ts b/src/docs/data/builders/menu.ts
index 6c90cb76..a7846582 100644
--- a/src/docs/data/builders/menu.ts
+++ b/src/docs/data/builders/menu.ts
@@ -7,6 +7,8 @@ import {
 	genElements,
 	genProps,
 	propsToOptions,
+	floatingSideAndAlignDataAttrs,
+	floatingSideDataAttr,
 } from '$docs/utils/index.js';
 
 import { menuEvents } from '$lib/builders/menu/events.js';
@@ -194,6 +196,7 @@ function getMenuMenuSchema(builderName: string) {
 	return elementSchema('menu', {
 		description: `The element which wraps the entire menu.`,
 		dataAttributes: [
+			...floatingSideAndAlignDataAttrs,
 			{
 				name: 'data-state',
 				value: ATTRS.OPEN_CLOSED,
@@ -228,6 +231,7 @@ export function getMenuArrowSchema(builderName: string) {
 	return elementSchema('arrow', {
 		description: `An optional arrow element which points to the menu's trigger.`,
 		dataAttributes: [
+			floatingSideDataAttr,
 			{
 				name: 'data-arrow',
 				value: ATTRS.TRUE,
@@ -370,6 +374,7 @@ function getMenuSubmenuSchema(name: string) {
 	return elementSchema('submenu', {
 		description: 'A submenu element displayed when its trigger is selected.',
 		dataAttributes: [
+			...floatingSideAndAlignDataAttrs,
 			{
 				name: 'data-state',
 				value: ATTRS.OPEN_CLOSED,
diff --git a/src/docs/data/builders/popover.ts b/src/docs/data/builders/popover.ts
index 9d978a74..d31d4173 100644
--- a/src/docs/data/builders/popover.ts
+++ b/src/docs/data/builders/popover.ts
@@ -1,6 +1,11 @@
 import { ATTRS, KBD, PROPS } from '$docs/constants.js';
 import type { KeyboardSchema } from '$docs/types.js';
-import { builderSchema, elementSchema } from '$docs/utils/index.js';
+import {
+	builderSchema,
+	elementSchema,
+	floatingSideAndAlignDataAttrs,
+	floatingSideDataAttr,
+} from '$docs/utils/index.js';
 import { popoverIdParts } from '$lib/index.js';
 import { popoverEvents } from '$lib/builders/popover/events.js';
 import type { BuilderData } from './index.js';
@@ -82,6 +87,7 @@ const trigger = elementSchema('trigger', {
 const content = elementSchema('content', {
 	description: 'The popover content.',
 	dataAttributes: [
+		...floatingSideAndAlignDataAttrs,
 		{
 			name: 'data-state',
 			value: ATTRS.OPEN_CLOSED,
@@ -112,6 +118,7 @@ const arrow = elementSchema('arrow', {
 	title: 'arrow',
 	description: 'The optional arrow element.',
 	dataAttributes: [
+		floatingSideDataAttr,
 		{
 			name: 'data-arrow',
 			value: ATTRS.TRUE,
diff --git a/src/docs/data/builders/select.ts b/src/docs/data/builders/select.ts
index 264c7016..6eb233a3 100644
--- a/src/docs/data/builders/select.ts
+++ b/src/docs/data/builders/select.ts
@@ -1,6 +1,11 @@
 import { ATTRS, KBD, PROPS, SEE } from '$docs/constants.js';
 import type { KeyboardSchema } from '$docs/types.js';
-import { builderSchema, elementSchema } from '$docs/utils/index.js';
+import {
+	builderSchema,
+	elementSchema,
+	floatingSideAndAlignDataAttrs,
+	floatingSideDataAttr,
+} from '$docs/utils/index.js';
 import { listboxIdParts } from '$lib/builders/listbox/create.js';
 import { selectEvents } from '$lib/builders/select/events.js';
 import type { BuilderData } from './index.js';
@@ -154,6 +159,7 @@ const trigger = elementSchema('trigger', {
 const menu = elementSchema('menu', {
 	description: 'The menu element',
 	dataAttributes: [
+		...floatingSideAndAlignDataAttrs,
 		{
 			name: 'data-melt-select-menu',
 			value: ATTRS.MELT('menu'),
@@ -216,6 +222,7 @@ const label = elementSchema('label', {
 const arrow = elementSchema('arrow', {
 	description: 'The optional arrow element',
 	dataAttributes: [
+		floatingSideDataAttr,
 		{
 			name: 'data-arrow',
 			value: ATTRS.TRUE,
diff --git a/src/docs/data/builders/tooltip.ts b/src/docs/data/builders/tooltip.ts
index 9ebdd71a..05243a89 100644
--- a/src/docs/data/builders/tooltip.ts
+++ b/src/docs/data/builders/tooltip.ts
@@ -1,6 +1,11 @@
 import { ATTRS, KBD, PROPS } from '$docs/constants.js';
 import type { KeyboardSchema } from '$docs/types.js';
-import { builderSchema, elementSchema } from '$docs/utils/index.js';
+import {
+	builderSchema,
+	elementSchema,
+	floatingSideAndAlignDataAttrs,
+	floatingSideDataAttr,
+} from '$docs/utils/index.js';
 import { tooltipIdParts } from '$lib/index.js';
 import { tooltipEvents } from '$lib/builders/tooltip/events.js';
 import type { BuilderData } from './index.js';
@@ -99,6 +104,7 @@ const content = elementSchema('content', {
 			name: 'data-state',
 			value: ATTRS.OPEN_CLOSED,
 		},
+		...floatingSideAndAlignDataAttrs,
 		{
 			name: 'data-melt-tooltip-content',
 			value: ATTRS.MELT('tooltip content'),
@@ -114,6 +120,7 @@ const arrow = elementSchema('arrow', {
 			name: 'data-arrow',
 			value: ATTRS.TRUE,
 		},
+		floatingSideDataAttr,
 		{
 			name: 'data-melt-tooltip-arrow',
 			value: ATTRS.MELT('tooltip arrow'),
diff --git a/src/docs/previews/dialog/alert/css/index.svelte b/src/docs/previews/dialog/alert/css/index.svelte
index a420fcf1..871b2204 100644
--- a/src/docs/previews/dialog/alert/css/index.svelte
+++ b/src/docs/previews/dialog/alert/css/index.svelte
@@ -22,8 +22,8 @@
 </script>
 
 <button use:melt={$trigger} class="trigger"> Delete Item </button>
-<div use:melt={$portalled}>
-	{#if $open}
+{#if $open}
+	<div use:melt={$portalled}>
 		<div use:melt={$overlay} class="overlay" />
 		<div
 			class="content"
@@ -51,8 +51,8 @@
 				<X class="size-4" />
 			</button>
 		</div>
-	{/if}
-</div>
+	</div>
+{/if}
 
 <style>
 	.trigger {
diff --git a/src/docs/previews/dialog/alert/tailwind/index.svelte b/src/docs/previews/dialog/alert/tailwind/index.svelte
index e2d0c132..442b16f3 100644
--- a/src/docs/previews/dialog/alert/tailwind/index.svelte
+++ b/src/docs/previews/dialog/alert/tailwind/index.svelte
@@ -29,8 +29,8 @@
 	Delete Item
 </button>
 
-<div class="force-dark" use:melt={$portalled}>
-	{#if $open}
+{#if $open}
+	<div class="force-dark" use:melt={$portalled}>
 		<div use:melt={$overlay} class="fixed inset-0 z-50 bg-black/50" />
 		<div
 			class="fixed left-[50%] top-[50%] z-50 max-h-[85vh] w-[90vw]
@@ -78,5 +78,5 @@
 				<X class="size-4" />
 			</button>
 		</div>
-	{/if}
-</div>
+	</div>
+{/if}
diff --git a/src/docs/previews/dialog/controlled/css/index.svelte b/src/docs/previews/dialog/controlled/css/index.svelte
index 67dd5241..289b8a5e 100644
--- a/src/docs/previews/dialog/controlled/css/index.svelte
+++ b/src/docs/previews/dialog/controlled/css/index.svelte
@@ -25,8 +25,8 @@
 </script>
 
 <button use:melt={$trigger} class="trigger"> Open Dialog </button>
-<div use:melt={$portalled}>
-	{#if $open}
+{#if $open}
+	<div use:melt={$portalled}>
 		<div use:melt={$overlay} class="overlay" />
 		<div
 			class="content"
@@ -59,8 +59,8 @@
 				<X class="size-4" />
 			</button>
 		</div>
-	{/if}
-</div>
+	</div>
+{/if}
 
 <style lang="postcss">
 	.trigger {
diff --git a/src/docs/previews/dialog/controlled/tailwind/index.svelte b/src/docs/previews/dialog/controlled/tailwind/index.svelte
index 5b9c1bec..fa0dfdd7 100644
--- a/src/docs/previews/dialog/controlled/tailwind/index.svelte
+++ b/src/docs/previews/dialog/controlled/tailwind/index.svelte
@@ -31,8 +31,8 @@
 >
 	Open Dialog
 </button>
-<div class="force-dark" use:melt={$portalled}>
-	{#if $open}
+{#if $open}
+	<div class="force-dark" use:melt={$portalled}>
 		<div use:melt={$overlay} class="fixed inset-0 z-50 bg-black/50" />
 		<div
 			class="fixed left-[50%] top-[50%] z-50 max-h-[85vh] w-[90vw]
@@ -101,5 +101,5 @@
 				<X class="size-4" />
 			</button>
 		</div>
-	{/if}
-</div>
+	</div>
+{/if}
diff --git a/src/docs/previews/dialog/drawer/css/index.svelte b/src/docs/previews/dialog/drawer/css/index.svelte
index d03a33d7..05cc5385 100644
--- a/src/docs/previews/dialog/drawer/css/index.svelte
+++ b/src/docs/previews/dialog/drawer/css/index.svelte
@@ -21,8 +21,8 @@
 </script>
 
 <button use:melt={$trigger} class="trigger"> View Notifications </button>
-<div use:melt={$portalled}>
-	{#if $open}
+{#if $open}
+	<div use:melt={$portalled}>
 		<div
 			use:melt={$overlay}
 			class="overlay"
@@ -57,8 +57,8 @@
 				</div>
 			</section>
 		</div>
-	{/if}
-</div>
+	</div>
+{/if}
 
 <style>
 	.trigger {
diff --git a/src/docs/previews/dialog/drawer/tailwind/index.svelte b/src/docs/previews/dialog/drawer/tailwind/index.svelte
index 916af375..b516de07 100644
--- a/src/docs/previews/dialog/drawer/tailwind/index.svelte
+++ b/src/docs/previews/dialog/drawer/tailwind/index.svelte
@@ -28,8 +28,8 @@
 >
 	View Notifications
 </button>
-<div class="force-dark" use:melt={$portalled}>
-	{#if $open}
+{#if $open}
+	<div class="force-dark" use:melt={$portalled}>
 		<div
 			use:melt={$overlay}
 			class="fixed inset-0 z-50 bg-black/50"
@@ -88,5 +88,5 @@
 				</div>
 			</section>
 		</div>
-	{/if}
-</div>
+	</div>
+{/if}
diff --git a/src/docs/previews/dialog/main/css/index.svelte b/src/docs/previews/dialog/main/css/index.svelte
index e9df12ab..dee12837 100644
--- a/src/docs/previews/dialog/main/css/index.svelte
+++ b/src/docs/previews/dialog/main/css/index.svelte
@@ -19,8 +19,8 @@
 </script>
 
 <button use:melt={$trigger} class="trigger"> Open Dialog </button>
-<div use:melt={$portalled}>
-	{#if $open}
+{#if $open}
+	<div use:melt={$portalled}>
 		<div use:melt={$overlay} class="overlay" />
 		<div
 			class="content"
@@ -53,8 +53,8 @@
 				<X class="size-4" />
 			</button>
 		</div>
-	{/if}
-</div>
+	</div>
+{/if}
 
 <style lang="postcss">
 	.trigger {
diff --git a/src/docs/previews/dialog/main/tailwind/index.svelte b/src/docs/previews/dialog/main/tailwind/index.svelte
index add998df..a64e1d1c 100644
--- a/src/docs/previews/dialog/main/tailwind/index.svelte
+++ b/src/docs/previews/dialog/main/tailwind/index.svelte
@@ -29,8 +29,8 @@
 	Open Dialog
 </button>
 
-<div class="force-dark" use:melt={$portalled}>
-	{#if $open}
+{#if $open}
+	<div class="force-dark" use:melt={$portalled}>
 		<div
 			use:melt={$overlay}
 			class="fixed inset-0 z-50 bg-black/50"
@@ -100,5 +100,5 @@
 				<X class="size-4" />
 			</button>
 		</div>
-	{/if}
-</div>
+	</div>
+{/if}
diff --git a/src/docs/previews/dialog/nested/css/index.svelte b/src/docs/previews/dialog/nested/css/index.svelte
index 1e753b0d..88a82051 100644
--- a/src/docs/previews/dialog/nested/css/index.svelte
+++ b/src/docs/previews/dialog/nested/css/index.svelte
@@ -36,8 +36,8 @@
 </script>
 
 <button use:melt={$trigger} class="trigger"> Open Dialog </button>
-<div use:melt={$portalled}>
-	{#if $open}
+{#if $open}
+	<div use:melt={$portalled}>
 		<div use:melt={$overlay} class="overlay" />
 		<div
 			class="content"
@@ -62,11 +62,11 @@
 				<X />
 			</button>
 		</div>
-	{/if}
-</div>
+	</div>
+{/if}
 
-<div use:melt={$portalledNested}>
-	{#if $openNested}
+{#if $openNested}
+	<div use:melt={$portalledNested}>
 		<div use:melt={$overlayNested} class="overlay overlay-nested" />
 		<div
 			class="content content-nested"
@@ -90,8 +90,8 @@
 				<X />
 			</button>
 		</div>
-	{/if}
-</div>
+	</div>
+{/if}
 
 <style>
 	.trigger {
diff --git a/src/docs/previews/dialog/nested/tailwind/index.svelte b/src/docs/previews/dialog/nested/tailwind/index.svelte
index 83a28825..852b639a 100644
--- a/src/docs/previews/dialog/nested/tailwind/index.svelte
+++ b/src/docs/previews/dialog/nested/tailwind/index.svelte
@@ -38,8 +38,8 @@
 >
 	Open Dialog
 </button>
-<div class="force-dark" use:melt={$portalled}>
-	{#if $open}
+{#if $open}
+	<div class="force-dark" use:melt={$portalled}>
 		<div use:melt={$overlay} class="fixed inset-0 z-50 bg-black/50" />
 		<div
 			class="fixed left-[50%] top-[50%] z-50 max-h-[85vh] w-[90vw]
@@ -75,8 +75,8 @@
 					Open second
 				</button>
 			</div>
-			<div class="force-dark" use:melt={$portalledNested}>
-				{#if $openNested}
+			{#if $openNested}
+				<div class="force-dark" use:melt={$portalledNested}>
 					<div
 						use:melt={$overlayNested}
 						class="fixed inset-0 z-50 bg-black/75"
@@ -124,8 +124,8 @@
 							<X class="size-4" />
 						</button>
 					</div>
-				{/if}
-			</div>
+				</div>
+			{/if}
 		</div>
 		<button
 			use:melt={$close}
@@ -135,5 +135,5 @@
 		>
 			<X />
 		</button>
-	{/if}
-</div>
+	</div>
+{/if}
diff --git a/src/docs/utils/content.ts b/src/docs/utils/content.ts
index 9fca1509..498bc192 100644
--- a/src/docs/utils/content.ts
+++ b/src/docs/utils/content.ts
@@ -136,3 +136,16 @@ export function elementSchema(name: string, schema: ElementSchema): APISchema {
 		events: customEvents,
 	};
 }
+
+export const floatingSideDataAttr = {
+	name: 'data-side',
+	value: "'top' | 'right' | 'bottom' | 'left'",
+};
+
+export const floatingSideAndAlignDataAttrs = [
+	floatingSideDataAttr,
+	{
+		name: 'data-align',
+		value: "'start' | 'center' | 'end'",
+	},
+];
diff --git a/src/lib/builders/accordion/create.ts b/src/lib/builders/accordion/create.ts
index 3fc78ee2..ddad700b 100644
--- a/src/lib/builders/accordion/create.ts
+++ b/src/lib/builders/accordion/create.ts
@@ -59,9 +59,10 @@ export const createAccordion = <Multiple extends boolean = false>(
 	});
 
 	const root = makeElement(name(), {
-		returned: () => ({
-			'data-melt-id': meltIds.root,
-		}),
+		returned: () =>
+			({
+				'data-melt-id': meltIds.root,
+			} as const),
 	});
 
 	const parseItemProps = (props: AccordionItemProps) => {
@@ -89,7 +90,7 @@ export const createAccordion = <Multiple extends boolean = false>(
 				return {
 					'data-state': isSelected(itemValue, $value) ? 'open' : 'closed',
 					'data-disabled': disabledAttr(disabled),
-				};
+				} as const;
 			};
 		},
 	});
@@ -108,7 +109,7 @@ export const createAccordion = <Multiple extends boolean = false>(
 					'data-disabled': disabledAttr(disabled),
 					'data-value': itemValue,
 					'data-state': isSelected(itemValue, $value) ? 'open' : 'closed',
-				};
+				} as const;
 			};
 		},
 		action: (node: HTMLElement): MeltActionReturn<AccordionEvents['trigger']> => {
@@ -182,7 +183,7 @@ export const createAccordion = <Multiple extends boolean = false>(
 					style: styleToString({
 						display: isVisible ? undefined : 'none',
 					}),
-				};
+				} as const;
 			};
 		},
 		action: (node: HTMLElement) => {
@@ -210,7 +211,7 @@ export const createAccordion = <Multiple extends boolean = false>(
 					role: 'heading',
 					'aria-level': level,
 					'data-heading-level': level,
-				};
+				} as const;
 			};
 		},
 	});
diff --git a/src/lib/builders/avatar/create.ts b/src/lib/builders/avatar/create.ts
index 14be4549..3d2389a0 100644
--- a/src/lib/builders/avatar/create.ts
+++ b/src/lib/builders/avatar/create.ts
@@ -54,7 +54,7 @@ export const createAvatar = (props?: CreateAvatarProps) => {
 			return {
 				src: $src,
 				style: imageStyles,
-			};
+			} as const;
 		},
 	});
 
@@ -69,7 +69,7 @@ export const createAvatar = (props?: CreateAvatarProps) => {
 						  })
 						: undefined,
 				hidden: $loadingStatus === 'loaded' ? true : undefined,
-			};
+			} as const;
 		},
 	});
 
diff --git a/src/lib/builders/calendar/create.ts b/src/lib/builders/calendar/create.ts
index b3073b0a..0f6fd1bd 100644
--- a/src/lib/builders/calendar/create.ts
+++ b/src/lib/builders/calendar/create.ts
@@ -44,7 +44,7 @@ import { derived, writable } from 'svelte/store';
 import type { CalendarEvents } from './events.js';
 import type { CalendarValue, CreateCalendarProps } from './types.js';
 
-const defaults = {
+export const defaults = {
 	isDateDisabled: undefined,
 	isDateUnavailable: undefined,
 	value: undefined,
@@ -286,7 +286,7 @@ export function createCalendar<
 				'data-invalid': $isInvalid ? '' : undefined,
 				'data-disabled': $disabled ? '' : undefined,
 				'data-readonly': $readonly ? '' : undefined,
-			};
+			} as const;
 		},
 		action: (node: HTMLElement): MeltActionReturn<CalendarEvents['calendar']> => {
 			/**
@@ -323,7 +323,7 @@ export function createCalendar<
 			return {
 				'aria-hidden': true,
 				'data-disabled': $disabled ? '' : undefined,
-			};
+			} as const;
 		},
 	});
 
@@ -340,11 +340,11 @@ export function createCalendar<
 			return {
 				tabindex: -1,
 				role: 'grid',
-				'aria-readonly': $readonly ? ('true' as const) : undefined,
-				'aria-disabled': $disabled ? ('true' as const) : undefined,
+				'aria-readonly': $readonly ? 'true' : undefined,
+				'aria-disabled': $disabled ? 'true' : undefined,
 				'data-readonly': $readonly ? '' : undefined,
 				'data-disabled': $disabled ? '' : undefined,
-			};
+			} as const;
 		},
 	});
 
@@ -362,10 +362,10 @@ export function createCalendar<
 				role: 'button',
 				type: 'button' as const,
 				'aria-label': 'Previous',
-				'aria-disabled': disabled ? ('true' as const) : undefined,
+				'aria-disabled': disabled ? 'true' : undefined,
 				'data-disabled': disabled ? '' : undefined,
 				disabled: disabled ? true : undefined,
-			};
+			} as const;
 		},
 		action: (node: HTMLElement): MeltActionReturn<CalendarEvents['prevButton']> => {
 			const unsub = executeCallbacks(
@@ -394,10 +394,10 @@ export function createCalendar<
 				role: 'button',
 				type: 'button' as const,
 				'aria-label': 'Next',
-				'aria-disabled': disabled ? ('true' as const) : undefined,
+				'aria-disabled': disabled ? 'true' : undefined,
 				'data-disabled': disabled ? '' : undefined,
 				disabled: disabled ? true : undefined,
-			};
+			} as const;
 		},
 		action: (node: HTMLElement): MeltActionReturn<CalendarEvents['nextButton']> => {
 			const unsub = executeCallbacks(
@@ -514,20 +514,48 @@ export function createCalendar<
 	 * Updates the displayed months based on changes in the placeholder value,
 	 * which determines the months to show in the calendar.
 	 */
-	effect(
-		[placeholder, weekStartsOn, locale, fixedWeeks, numberOfMonths],
-		([$placeholder, $weekStartsOn, $locale, $fixedWeeks, $numberOfMonths]) => {
-			if (!isBrowser || !$placeholder) return;
+	effect([placeholder], ([$placeholder]) => {
+		if (!isBrowser || !$placeholder) return;
 
-			const $visibleMonths = visibleMonths.get();
+		const $visibleMonths = visibleMonths.get();
 
-			/**
-			 * If the placeholder's month is already in the visible months,
-			 * we don't need to do anything.
-			 */
-			if ($visibleMonths.some((month) => isSameMonth(month, $placeholder))) {
-				return;
-			}
+		/**
+		 * If the placeholder's month is already in the visible months,
+		 * we don't need to do anything.
+		 */
+		if ($visibleMonths.some((month) => isSameMonth(month, $placeholder))) {
+			return;
+		}
+
+		const $weekStartsOn = weekStartsOn.get();
+		const $locale = locale.get();
+		const $fixedWeeks = fixedWeeks.get();
+		const $numberOfMonths = numberOfMonths.get();
+
+		const defaultMonthProps = {
+			weekStartsOn: $weekStartsOn,
+			locale: $locale,
+			fixedWeeks: $fixedWeeks,
+			numberOfMonths: $numberOfMonths,
+		};
+
+		months.set(
+			createMonths({
+				...defaultMonthProps,
+				dateObj: $placeholder,
+			})
+		);
+	});
+
+	/**
+	 * Updates the displayed months based on changes in the the options values,
+	 * which determines the months to show in the calendar.
+	 */
+	effect(
+		[weekStartsOn, locale, fixedWeeks, numberOfMonths],
+		([$weekStartsOn, $locale, $fixedWeeks, $numberOfMonths]) => {
+			const $placeholder = placeholder.get();
+			if (!isBrowser || !$placeholder) return;
 
 			const defaultMonthProps = {
 				weekStartsOn: $weekStartsOn,
diff --git a/src/lib/builders/checkbox/create.ts b/src/lib/builders/checkbox/create.ts
index 3e33ba85..b139d4f1 100644
--- a/src/lib/builders/checkbox/create.ts
+++ b/src/lib/builders/checkbox/create.ts
@@ -72,7 +72,7 @@ export function createCheckbox(props?: CreateCheckboxProps) {
 		stores: [checked, name, value, required, disabled],
 		returned: ([$checked, $name, $value, $required, $disabled]) => {
 			return {
-				type: 'checkbox' as const,
+				type: 'checkbox',
 				'aria-hidden': true,
 				hidden: true,
 				tabindex: -1,
diff --git a/src/lib/builders/collapsible/create.ts b/src/lib/builders/collapsible/create.ts
index 7c0a264b..bd8022bf 100644
--- a/src/lib/builders/collapsible/create.ts
+++ b/src/lib/builders/collapsible/create.ts
@@ -32,10 +32,11 @@ export function createCollapsible(props?: CreateCollapsibleProps) {
 
 	const root = makeElement(name(), {
 		stores: [open, disabled],
-		returned: ([$open, $disabled]) => ({
-			'data-state': $open ? 'open' : 'closed',
-			'data-disabled': disabledAttr($disabled),
-		}),
+		returned: ([$open, $disabled]) =>
+			({
+				'data-state': $open ? 'open' : 'closed',
+				'data-disabled': disabledAttr($disabled),
+			} as const),
 	});
 
 	const trigger = makeElement(name('trigger'), {
@@ -72,7 +73,7 @@ export function createCollapsible(props?: CreateCollapsibleProps) {
 			hidden: $isVisible ? undefined : true,
 			style: styleToString({
 				display: $isVisible ? undefined : 'none',
-			}),
+			} as const),
 		}),
 	});
 
diff --git a/src/lib/builders/context-menu/create.ts b/src/lib/builders/context-menu/create.ts
index 11099d65..7365de14 100644
--- a/src/lib/builders/context-menu/create.ts
+++ b/src/lib/builders/context-menu/create.ts
@@ -159,9 +159,10 @@ export function createContextMenu(props?: CreateContextMenuProps) {
 					unsubPopper();
 					if (!$isVisible || !$rootActiveTrigger) return;
 					tick().then(() => {
+						unsubPopper();
 						setMeltMenuAttribute(node, selector);
 						const $virtual = virtual.get();
-						const popper = usePopper(node, {
+						unsubPopper = usePopper(node, {
 							anchorElement: $virtual ? $virtual : $rootActiveTrigger,
 							open: rootOpen,
 							options: {
@@ -177,9 +178,7 @@ export function createContextMenu(props?: CreateContextMenuProps) {
 								portal: getPortalDestination(node, $portal),
 								escapeKeydown: $closeOnEscape ? undefined : null,
 							},
-						});
-						if (!popper || !popper.destroy) return;
-						unsubPopper = popper.destroy;
+						}).destroy;
 					});
 				}
 			);
diff --git a/src/lib/builders/date-field/create.ts b/src/lib/builders/date-field/create.ts
index 7f761e1f..1052352f 100644
--- a/src/lib/builders/date-field/create.ts
+++ b/src/lib/builders/date-field/create.ts
@@ -274,7 +274,7 @@ export function createDateField(props?: CreateDateFieldProps) {
 				id: $labelId,
 				'data-invalid': $isInvalid ? '' : undefined,
 				'data-disabled': $disabled ? '' : undefined,
-			};
+			} as const;
 		},
 		action: (node: HTMLElement) => {
 			const unsub = executeCallbacks(
@@ -307,7 +307,7 @@ export function createDateField(props?: CreateDateFieldProps) {
 				id: $validationId,
 				'data-invalid': $isInvalid ? '' : undefined,
 				style: $isInvalid ? undefined : validStyle,
-			};
+			} as const;
 		},
 	});
 
@@ -346,11 +346,11 @@ export function createDateField(props?: CreateDateFieldProps) {
 				id: $ids.field,
 				'aria-labelledby': $ids.label,
 				'aria-describedby': describedBy,
-				'aria-disabled': $disabled ? ('true' as const) : undefined,
-				'aria-readonly': $readonly ? ('true' as const) : undefined,
+				'aria-disabled': $disabled ? 'true' : undefined,
+				'aria-readonly': $readonly ? 'true' : undefined,
 				'data-invalid': $isInvalid ? '' : undefined,
 				'data-disabled': $disabled ? '' : undefined,
-			};
+			} as const;
 		},
 		// even if we don't need the element we need to specify it
 		// or TS will complain when svelte tries to pass it
@@ -443,9 +443,9 @@ export function createDateField(props?: CreateDateFieldProps) {
 				const inReadonlySegments = $readonlySegmentsSet.has(part);
 				const defaultAttrs = {
 					...getSegmentAttrs(part, props),
-					'aria-invalid': $isInvalid ? ('true' as const) : undefined,
-					'aria-disabled': $disabled ? ('true' as const) : undefined,
-					'aria-readonly': $readonly || inReadonlySegments ? ('true' as const) : undefined,
+					'aria-invalid': $isInvalid ? 'true' : undefined,
+					'aria-disabled': $disabled ? 'true' : undefined,
+					'aria-readonly': $readonly || inReadonlySegments ? 'true' : undefined,
 					'data-invalid': $isInvalid ? '' : undefined,
 					'data-disabled': $disabled ? '' : undefined,
 					'data-segment': `${part}`,
@@ -466,7 +466,7 @@ export function createDateField(props?: CreateDateFieldProps) {
 					contenteditable: $readonly || inReadonlySegments || $disabled ? false : true,
 					'aria-describedby': describedBy,
 					tabindex: $disabled ? undefined : 0,
-				};
+				} as const;
 			};
 		},
 		action: (node: HTMLElement): MeltActionReturn<DateFieldEvents['segment']> =>
diff --git a/src/lib/builders/date-picker/create.ts b/src/lib/builders/date-picker/create.ts
index 3adbfce7..2bb4e2aa 100644
--- a/src/lib/builders/date-picker/create.ts
+++ b/src/lib/builders/date-picker/create.ts
@@ -16,6 +16,7 @@ import { pickerOpenFocus } from '$lib/internal/helpers/date/focus.js';
 import { createFormatter, dateStore, getDefaultDate } from '$lib/internal/helpers/date/index.js';
 import type { MeltActionReturn } from '$lib/internal/types.js';
 import type { DatePickerEvents } from './events.js';
+import { defaults as calendarDefaults } from '../calendar/create.js';
 
 const defaults = {
 	isDateDisabled: undefined,
@@ -36,6 +37,18 @@ const defaults = {
 	minValue: undefined,
 	maxValue: undefined,
 	weekdayFormat: 'narrow',
+	...omit(
+		calendarDefaults,
+		'isDateDisabled',
+		'isDateUnavailable',
+		'value',
+		'locale',
+		'disabled',
+		'readonly',
+		'minValue',
+		'maxValue',
+		'weekdayFormat'
+	),
 } satisfies CreateDatePickerProps;
 
 export function createDatePicker(props?: CreateDatePickerProps) {
@@ -83,7 +96,7 @@ export function createDatePicker(props?: CreateDatePickerProps) {
 				'aria-label': 'Open date picker',
 				'data-segment': 'trigger',
 				disabled: $disabled ? true : undefined,
-			};
+			} as const;
 		},
 		action: (node: HTMLElement): MeltActionReturn<DatePickerEvents['trigger']> => {
 			const unsubKeydown = addMeltEventListener(node, 'keydown', handleTriggerKeydown);
@@ -131,6 +144,18 @@ export function createDatePicker(props?: CreateDatePickerProps) {
 		calendar.options.maxValue.set($maxValue);
 	});
 
+	effect([options.numberOfMonths], ([$numberOfMonths]) => {
+		calendar.options.numberOfMonths.set($numberOfMonths);
+	});
+
+	effect([options.fixedWeeks], ([$fixedWeeks]) => {
+		calendar.options.fixedWeeks.set($fixedWeeks);
+	});
+
+	effect([options.weekStartsOn], ([$weekStartsOn]) => {
+		calendar.options.weekStartsOn.set($weekStartsOn);
+	});
+
 	const dateFieldOptions = omit(
 		dateField.options,
 		'locale',
diff --git a/src/lib/builders/date-range-field/create.ts b/src/lib/builders/date-range-field/create.ts
index 9997b79e..b003c376 100644
--- a/src/lib/builders/date-range-field/create.ts
+++ b/src/lib/builders/date-range-field/create.ts
@@ -182,7 +182,7 @@ export function createDateRangeField(props?: CreateDateRangeFieldProps) {
 				id: $labelId,
 				'data-invalid': $isInvalid ? '' : undefined,
 				'data-disabled': $disabled ? '' : undefined,
-			};
+			} as const;
 		},
 		action: (node: HTMLElement) => {
 			const unsub = executeCallbacks(
@@ -229,7 +229,7 @@ export function createDateRangeField(props?: CreateDateRangeFieldProps) {
 				'aria-labelledby': $ids.label,
 				'aria-describedby': describedBy,
 				'data-invalid': $isInvalid ? '' : undefined,
-			};
+			} as const;
 		},
 		action: () => {
 			getAnnouncer();
@@ -252,7 +252,7 @@ export function createDateRangeField(props?: CreateDateRangeFieldProps) {
 				id: $validationId,
 				'data-invalid': $isInvalid ? '' : undefined,
 				style: $isInvalid ? undefined : validStyle,
-			};
+			} as const;
 		},
 	});
 
diff --git a/src/lib/builders/date-range-picker/create.ts b/src/lib/builders/date-range-picker/create.ts
index 5f046587..66664ca4 100644
--- a/src/lib/builders/date-range-picker/create.ts
+++ b/src/lib/builders/date-range-picker/create.ts
@@ -95,7 +95,7 @@ export function createDateRangePicker(props?: CreateDateRangePickerProps) {
 				'aria-label': 'Open date picker',
 				'data-segment': 'trigger',
 				disabled: $disabled ? true : undefined,
-			};
+			} as const;
 		},
 		action: (node: HTMLElement): MeltActionReturn<DateRangePickerEvents['trigger']> => {
 			const unsubKeydown = addMeltEventListener(node, 'keydown', handleTriggerKeydown);
diff --git a/src/lib/builders/dialog/create.ts b/src/lib/builders/dialog/create.ts
index 9f028bb2..24e43af8 100644
--- a/src/lib/builders/dialog/create.ts
+++ b/src/lib/builders/dialog/create.ts
@@ -171,14 +171,14 @@ export function createDialog(props?: CreateDialogProps) {
 				role: role.get(),
 				'aria-describedby': $descriptionId,
 				'aria-labelledby': $titleId,
-				'aria-modal': $isVisible ? ('true' as const) : undefined,
+				'aria-modal': $isVisible ? 'true' : undefined,
 				'data-state': $open ? 'open' : 'closed',
 				tabindex: -1,
 				hidden: $isVisible ? undefined : true,
 				style: styleToString({
 					display: $isVisible ? undefined : 'none',
 				}),
-			};
+			} as const;
 		},
 
 		action: (node: HTMLElement) => {
@@ -186,26 +186,30 @@ export function createDialog(props?: CreateDialogProps) {
 			let deactivate = noop;
 
 			const destroy = executeCallbacks(
-				effect([open], ([$open]) => {
-					if (!$open) return;
-
-					const focusTrap = createFocusTrap({
-						immediate: false,
-						escapeDeactivates: true,
-						clickOutsideDeactivates: true,
-						returnFocusOnDeactivate: false,
-						fallbackFocus: node,
-					});
-
-					activate = focusTrap.activate;
-					deactivate = focusTrap.deactivate;
-					const ac = focusTrap.useFocusTrap(node);
-					if (ac && ac.destroy) {
-						return ac.destroy;
-					} else {
-						return focusTrap.deactivate;
+				effect(
+					[open, closeOnOutsideClick, closeOnEscape],
+					([$open, $closeOnOutsideClick, $closeOnEscape]) => {
+						if (!$open) return;
+
+						const focusTrap = createFocusTrap({
+							immediate: false,
+							escapeDeactivates: $closeOnEscape,
+							clickOutsideDeactivates: $closeOnOutsideClick,
+							allowOutsideClick: true,
+							returnFocusOnDeactivate: false,
+							fallbackFocus: node,
+						});
+
+						activate = focusTrap.activate;
+						deactivate = focusTrap.deactivate;
+						const ac = focusTrap.useFocusTrap(node);
+						if (ac && ac.destroy) {
+							return ac.destroy;
+						} else {
+							return focusTrap.deactivate;
+						}
 					}
-				}),
+				),
 				effect([closeOnOutsideClick, open], ([$closeOnOutsideClick, $open]) => {
 					return useModal(node, {
 						open: $open,
@@ -223,15 +227,7 @@ export function createDialog(props?: CreateDialogProps) {
 				effect([closeOnEscape], ([$closeOnEscape]) => {
 					if (!$closeOnEscape) return noop;
 
-					const escapeKeydown = useEscapeKeydown(node, {
-						handler: () => {
-							handleClose();
-						},
-					});
-					if (escapeKeydown && escapeKeydown.destroy) {
-						return escapeKeydown.destroy;
-					}
-					return noop;
+					return useEscapeKeydown(node, { handler: handleClose }).destroy;
 				}),
 
 				effect([isVisible], ([$isVisible]) => {
@@ -256,20 +252,16 @@ export function createDialog(props?: CreateDialogProps) {
 
 	const portalled = makeElement(name('portalled'), {
 		stores: portal,
-		returned: ($portal) => ({
-			'data-portal': portalAttr($portal),
-		}),
+		returned: ($portal) =>
+			({
+				'data-portal': portalAttr($portal),
+			} as const),
 		action: (node: HTMLElement) => {
 			const unsubPortal = effect([portal], ([$portal]) => {
 				if ($portal === null) return noop;
 				const portalDestination = getPortalDestination(node, $portal);
 				if (portalDestination === null) return noop;
-				const portalAction = usePortal(node, portalDestination);
-				if (portalAction && portalAction.destroy) {
-					return portalAction.destroy;
-				} else {
-					return noop;
-				}
+				return usePortal(node, portalDestination).destroy;
 			});
 
 			return {
@@ -282,16 +274,18 @@ export function createDialog(props?: CreateDialogProps) {
 
 	const title = makeElement(name('title'), {
 		stores: [ids.title],
-		returned: ([$titleId]) => ({
-			id: $titleId,
-		}),
+		returned: ([$titleId]) =>
+			({
+				id: $titleId,
+			} as const),
 	});
 
 	const description = makeElement(name('description'), {
 		stores: [ids.description],
-		returned: ([$descriptionId]) => ({
-			id: $descriptionId,
-		}),
+		returned: ([$descriptionId]) =>
+			({
+				id: $descriptionId,
+			} as const),
 	});
 
 	const close = makeElement(name('close'), {
diff --git a/src/lib/builders/hidden-input/create.ts b/src/lib/builders/hidden-input/create.ts
index 274ba916..2c9d73bc 100644
--- a/src/lib/builders/hidden-input/create.ts
+++ b/src/lib/builders/hidden-input/create.ts
@@ -29,7 +29,7 @@ export function createHiddenInput(props: CreateHiddenInputProps) {
 			return {
 				name: $name,
 				value: $value?.toString(),
-				'aria-hidden': 'true' as const,
+				'aria-hidden': 'true',
 				hidden: true,
 				disabled: $disabled,
 				required: $required,
@@ -41,7 +41,7 @@ export function createHiddenInput(props: CreateHiddenInputProps) {
 					margin: 0,
 					transform: 'translateX(-100%)',
 				}),
-			};
+			} as const;
 		},
 		action: (node: HTMLInputElement) => {
 			// When value changes, emit a change event
diff --git a/src/lib/builders/link-preview/create.ts b/src/lib/builders/link-preview/create.ts
index bb013909..f46b413e 100644
--- a/src/lib/builders/link-preview/create.ts
+++ b/src/lib/builders/link-preview/create.ts
@@ -20,7 +20,6 @@ import {
 	toWritableStores,
 	portalAttr,
 } from '$lib/internal/helpers/index.js';
-import { safeOnMount } from '$lib/internal/helpers/lifecycle.js';
 import { withGet, type WithGet } from '$lib/internal/helpers/withGet.js';
 import type { MeltActionReturn } from '$lib/internal/types.js';
 import { writable, type Readable } from 'svelte/store';
@@ -28,6 +27,7 @@ import { generateIds } from '../../internal/helpers/id.js';
 import { omit } from '../../internal/helpers/object.js';
 import type { LinkPreviewEvents } from './events.js';
 import type { CreateLinkPreviewProps } from './types.js';
+import { tick } from 'svelte';
 
 type LinkPreviewParts = 'trigger' | 'content' | 'arrow';
 const { name } = createElHelpers<LinkPreviewParts>('hover-card');
@@ -115,15 +115,16 @@ export function createLinkPreview(props: CreateLinkPreviewProps = {}) {
 		stores: [open, ids.trigger, ids.content],
 		returned: ([$open, $triggerId, $contentId]) => {
 			return {
-				role: 'button' as const,
-				'aria-haspopup': 'dialog' as const,
+				role: 'button',
+				'aria-haspopup': 'dialog',
 				'aria-expanded': $open,
 				'data-state': $open ? 'open' : 'closed',
 				'aria-controls': $contentId,
 				id: $triggerId,
-			};
+			} as const;
 		},
 		action: (node: HTMLElement): MeltActionReturn<LinkPreviewEvents['trigger']> => {
+			activeTrigger.set(node);
 			const unsub = executeCallbacks(
 				addMeltEventListener(node, 'pointerenter', (e) => {
 					if (isTouch(e)) return;
@@ -163,7 +164,7 @@ export function createLinkPreview(props: CreateLinkPreviewProps = {}) {
 				id: $contentId,
 				'data-state': $isVisible ? 'open' : 'closed',
 				'data-portal': portalAttr($portal),
-			};
+			} as const;
 		},
 		action: (node: HTMLElement): MeltActionReturn<LinkPreviewEvents['content']> => {
 			let unsub = noop;
@@ -189,35 +190,37 @@ export function createLinkPreview(props: CreateLinkPreviewProps = {}) {
 					unsubPopper();
 					if (!$isVisible || !$activeTrigger) return;
 
-					const popper = usePopper(node, {
-						anchorElement: $activeTrigger,
-						open: open,
-						options: {
-							floating: $positioning,
-							modal: {
-								closeOnInteractOutside: $closeOnOutsideClick,
-								onClose: () => {
-									open.set(false);
-									$activeTrigger.focus();
-								},
-								shouldCloseOnInteractOutside: (e) => {
-									onOutsideClick.get()?.(e);
-									if (e.defaultPrevented) return false;
-									if (isHTMLElement($activeTrigger) && $activeTrigger.contains(e.target as Element))
-										return false;
-									return true;
+					tick().then(() => {
+						unsubPopper();
+						unsubPopper = usePopper(node, {
+							anchorElement: $activeTrigger,
+							open: open,
+							options: {
+								floating: $positioning,
+								modal: {
+									closeOnInteractOutside: $closeOnOutsideClick,
+									onClose: () => {
+										open.set(false);
+										$activeTrigger.focus();
+									},
+									shouldCloseOnInteractOutside: (e) => {
+										onOutsideClick.get()?.(e);
+										if (e.defaultPrevented) return false;
+										if (
+											isHTMLElement($activeTrigger) &&
+											$activeTrigger.contains(e.target as Element)
+										)
+											return false;
+										return true;
+									},
+									open: $isVisible,
 								},
-								open: $isVisible,
+								portal: getPortalDestination(node, $portal),
+								focusTrap: null,
+								escapeKeydown: $closeOnEscape ? undefined : null,
 							},
-							portal: getPortalDestination(node, $portal),
-							focusTrap: null,
-							escapeKeydown: $closeOnEscape ? undefined : null,
-						},
+						}).destroy;
 					});
-
-					if (popper && popper.destroy) {
-						unsubPopper = popper.destroy;
-					}
 				}
 			);
 
@@ -260,14 +263,15 @@ export function createLinkPreview(props: CreateLinkPreviewProps = {}) {
 
 	const arrow = makeElement(name('arrow'), {
 		stores: arrowSize,
-		returned: ($arrowSize) => ({
-			'data-arrow': true,
-			style: styleToString({
-				position: 'absolute',
-				width: `var(--arrow-size, ${$arrowSize}px)`,
-				height: `var(--arrow-size, ${$arrowSize}px)`,
-			}),
-		}),
+		returned: ($arrowSize) =>
+			({
+				'data-arrow': true,
+				style: styleToString({
+					position: 'absolute',
+					width: `var(--arrow-size, ${$arrowSize}px)`,
+					height: `var(--arrow-size, ${$arrowSize}px)`,
+				}),
+			} as const),
 	});
 
 	effect([containSelection], ([$containSelection]) => {
@@ -292,12 +296,6 @@ export function createLinkPreview(props: CreateLinkPreviewProps = {}) {
 		};
 	});
 
-	safeOnMount(() => {
-		const triggerEl = document.getElementById(ids.trigger.get());
-		if (!triggerEl) return;
-		activeTrigger.set(triggerEl);
-	});
-
 	effect([open], ([$open]) => {
 		if (!isBrowser || !$open) {
 			hasSelection.set(false);
diff --git a/src/lib/builders/listbox/create.ts b/src/lib/builders/listbox/create.ts
index f15a19fe..461f3368 100644
--- a/src/lib/builders/listbox/create.ts
+++ b/src/lib/builders/listbox/create.ts
@@ -32,14 +32,12 @@ import {
 	prev,
 	removeHighlight,
 	removeScroll,
-	sleep,
 	stripValues,
 	styleToString,
 	toWritableStores,
 	toggle,
 	withGet,
 } from '$lib/internal/helpers/index.js';
-import { safeOnMount } from '$lib/internal/helpers/lifecycle.js';
 import type { Defaults, MeltActionReturn } from '$lib/internal/types.js';
 import { dequal as deepEqual } from 'dequal';
 import { tick } from 'svelte';
@@ -209,12 +207,6 @@ export function createListbox<
 	async function openMenu() {
 		open.set(true);
 
-		const triggerEl = document.getElementById(ids.trigger.get());
-		if (!triggerEl) return;
-
-		// The active trigger is used to anchor the menu to the input element.
-		activeTrigger.set(triggerEl);
-
 		// Wait a tick for the menu to open then highlight the selected item.
 		await tick();
 
@@ -227,8 +219,7 @@ export function createListbox<
 	}
 
 	/** Closes the menu & clears the active trigger */
-	async function closeMenu() {
-		await sleep(0);
+	function closeMenu() {
 		open.set(false);
 		highlightedItem.set(null);
 	}
@@ -292,6 +283,7 @@ export function createListbox<
 			} as const;
 		},
 		action: (node: HTMLElement): MeltActionReturn<ListboxEvents['trigger']> => {
+			activeTrigger.set(node);
 			const isInput = isHTMLInputElement(node);
 
 			const unsubscribe = executeCallbacks(
@@ -368,7 +360,10 @@ export function createListbox<
 						return;
 					}
 					// Pressing enter with a highlighted item should select it.
-					if (e.key === kbd.ENTER || (e.key === kbd.SPACE && isHTMLButtonElement(node))) {
+					if (
+						(e.key === kbd.ENTER && !e.isComposing) ||
+						(e.key === kbd.SPACE && isHTMLButtonElement(node))
+					) {
 						e.preventDefault();
 						const $highlightedItem = highlightedItem.get();
 						if ($highlightedItem) {
@@ -450,6 +445,7 @@ export function createListbox<
 
 			return {
 				destroy() {
+					activeTrigger.set(null);
 					unsubscribe();
 					unsubEscapeKeydown();
 				},
@@ -481,39 +477,39 @@ export function createListbox<
 
 						if (!$isVisible || !$activeTrigger) return;
 
-						const ignoreHandler = createClickOutsideIgnore(ids.trigger.get());
-
-						const popper = usePopper(node, {
-							anchorElement: $activeTrigger,
-							open,
-							options: {
-								floating: $positioning,
-								focusTrap: null,
-								modal: {
-									closeOnInteractOutside: $closeOnOutsideClick,
-									onClose: closeMenu,
-									open: $isVisible,
-									shouldCloseOnInteractOutside: (e) => {
-										onOutsideClick.get()?.(e);
-										if (e.defaultPrevented) return false;
-										const target = e.target;
-										if (!isElement(target)) return false;
-										if (target === $activeTrigger || $activeTrigger.contains(target)) {
-											return false;
-										}
-										// return opposite of the result of the ignoreHandler
-										if (ignoreHandler(e)) return false;
-										return true;
+						tick().then(() => {
+							unsubPopper();
+							const ignoreHandler = createClickOutsideIgnore(ids.trigger.get());
+
+							unsubPopper = usePopper(node, {
+								anchorElement: $activeTrigger,
+								open,
+								options: {
+									floating: $positioning,
+									focusTrap: null,
+									modal: {
+										closeOnInteractOutside: $closeOnOutsideClick,
+										onClose: closeMenu,
+										open: $isVisible,
+										shouldCloseOnInteractOutside: (e) => {
+											onOutsideClick.get()?.(e);
+											if (e.defaultPrevented) return false;
+											const target = e.target;
+											if (!isElement(target)) return false;
+											if (target === $activeTrigger || $activeTrigger.contains(target)) {
+												return false;
+											}
+											// return opposite of the result of the ignoreHandler
+											if (ignoreHandler(e)) return false;
+											return true;
+										},
 									},
-								},
 
-								escapeKeydown: null,
-								portal: getPortalDestination(node, $portal),
-							},
+									escapeKeydown: null,
+									portal: getPortalDestination(node, $portal),
+								},
+							}).destroy;
 						});
-						if (popper && popper.destroy) {
-							unsubPopper = popper.destroy;
-						}
 					}
 				)
 			);
@@ -538,7 +534,7 @@ export function createListbox<
 			return {
 				id: $labelId,
 				for: $triggerId,
-			};
+			} as const;
 		},
 		action: labelAction,
 	});
@@ -596,18 +592,20 @@ export function createListbox<
 
 	const group = makeElement(name('group'), {
 		returned: () => {
-			return (groupId: string) => ({
-				role: 'group',
-				'aria-labelledby': groupId,
-			});
+			return (groupId: string) =>
+				({
+					role: 'group',
+					'aria-labelledby': groupId,
+				} as const);
 		},
 	});
 
 	const groupLabel = makeElement(name('group-label'), {
 		returned: () => {
-			return (groupId: string) => ({
-				id: groupId,
-			});
+			return (groupId: string) =>
+				({
+					id: groupId,
+				} as const);
 		},
 	});
 
@@ -623,34 +621,21 @@ export function createListbox<
 
 	const arrow = makeElement(name('arrow'), {
 		stores: arrowSize,
-		returned: ($arrowSize) => ({
-			'data-arrow': true,
-			style: styleToString({
-				position: 'absolute',
-				width: `var(--arrow-size, ${$arrowSize}px)`,
-				height: `var(--arrow-size, ${$arrowSize}px)`,
-			}),
-		}),
+		returned: ($arrowSize) =>
+			({
+				'data-arrow': true,
+				style: styleToString({
+					position: 'absolute',
+					width: `var(--arrow-size, ${$arrowSize}px)`,
+					height: `var(--arrow-size, ${$arrowSize}px)`,
+				}),
+			} as const),
 	});
 
 	/* ------------------- */
 	/* LIFECYCLE & EFFECTS */
 	/* ------------------- */
 
-	safeOnMount(() => {
-		if (!isBrowser) return;
-		const menuEl = document.getElementById(ids.menu.get());
-
-		const triggerEl = document.getElementById(ids.trigger.get());
-		if (triggerEl) {
-			activeTrigger.set(triggerEl);
-		}
-
-		if (!menuEl) return;
-		const selectedEl = menuEl.querySelector('[data-selected]');
-		if (!isHTMLElement(selectedEl)) return;
-	});
-
 	/**
 	 * Handles moving the `data-highlighted` attribute between items when
 	 * the user moves their pointer or navigates with their keyboard.
@@ -668,18 +653,9 @@ export function createListbox<
 		});
 	});
 
-	effect([open], ([$open]) => {
-		if (!isBrowser) return;
-
-		let unsubScroll = noop;
-
-		if (preventScroll.get() && $open) {
-			unsubScroll = removeScroll();
-		}
-
-		return () => {
-			unsubScroll();
-		};
+	effect([open, preventScroll], ([$open, $preventScroll]) => {
+		if (!isBrowser || !$open || !$preventScroll) return;
+		return removeScroll();
 	});
 
 	return {
diff --git a/src/lib/builders/listbox/types.ts b/src/lib/builders/listbox/types.ts
index a35c9a01..550b0ef5 100644
--- a/src/lib/builders/listbox/types.ts
+++ b/src/lib/builders/listbox/types.ts
@@ -30,7 +30,7 @@ export type CreateListboxProps<
 
 	/**
 	 * The size of the arrow in pixels.
-	 * @default 8
+	 * @default undefined
 	 */
 	arrowSize?: number;
 
diff --git a/src/lib/builders/menu/create.ts b/src/lib/builders/menu/create.ts
index c275a30a..9c013dbd 100644
--- a/src/lib/builders/menu/create.ts
+++ b/src/lib/builders/menu/create.ts
@@ -185,8 +185,9 @@ export function createMenuBuilder(opts: _MenuBuilderOptions) {
 					unsubPopper();
 					if (!$isVisible || !$rootActiveTrigger) return;
 					tick().then(() => {
+						unsubPopper();
 						setMeltMenuAttribute(node, selector);
-						const popper = usePopper(node, {
+						unsubPopper = usePopper(node, {
 							anchorElement: $rootActiveTrigger,
 							open: rootOpen,
 							options: {
@@ -214,11 +215,7 @@ export function createMenuBuilder(opts: _MenuBuilderOptions) {
 								portal: getPortalDestination(node, $portal),
 								escapeKeydown: $closeOnEscape ? undefined : null,
 							},
-						});
-
-						if (popper && popper.destroy) {
-							unsubPopper = popper.destroy;
-						}
+						}).destroy;
 					});
 				}
 			);
@@ -326,14 +323,15 @@ export function createMenuBuilder(opts: _MenuBuilderOptions) {
 
 	const rootArrow = makeElement(name('arrow'), {
 		stores: arrowSize,
-		returned: ($arrowSize) => ({
-			'data-arrow': true,
-			style: styleToString({
-				position: 'absolute',
-				width: `var(--arrow-size, ${$arrowSize}px)`,
-				height: `var(--arrow-size, ${$arrowSize}px)`,
-			}),
-		}),
+		returned: ($arrowSize) =>
+			({
+				'data-arrow': true,
+				style: styleToString({
+					position: 'absolute',
+					width: `var(--arrow-size, ${$arrowSize}px)`,
+					height: `var(--arrow-size, ${$arrowSize}px)`,
+				}),
+			} as const),
 	});
 
 	const overlay = makeElement(name('overlay'), {
@@ -369,12 +367,7 @@ export function createMenuBuilder(opts: _MenuBuilderOptions) {
 				if ($portal === null) return noop;
 				const portalDestination = getPortalDestination(node, $portal);
 				if (portalDestination === null) return noop;
-				const portalAction = usePortal(node, portalDestination);
-				if (portalAction && portalAction.destroy) {
-					return portalAction.destroy;
-				} else {
-					return noop;
-				}
+				return usePortal(node, portalDestination).destroy;
 			});
 
 			return {
@@ -392,7 +385,7 @@ export function createMenuBuilder(opts: _MenuBuilderOptions) {
 				role: 'menuitem',
 				tabindex: -1,
 				'data-orientation': 'vertical',
-			};
+			} as const;
 		},
 		action: (node: HTMLElement): MeltActionReturn<MenuEvents['item']> => {
 			setMeltMenuAttribute(node, selector);
@@ -452,18 +445,20 @@ export function createMenuBuilder(opts: _MenuBuilderOptions) {
 
 	const group = makeElement(name('group'), {
 		returned: () => {
-			return (groupId: string) => ({
-				role: 'group',
-				'aria-labelledby': groupId,
-			});
+			return (groupId: string) =>
+				({
+					role: 'group',
+					'aria-labelledby': groupId,
+				} as const);
 		},
 	});
 
 	const groupLabel = makeElement(name('group-label'), {
 		returned: () => {
-			return (groupId: string) => ({
-				id: groupId,
-			});
+			return (groupId: string) =>
+				({
+					id: groupId,
+				} as const);
 		},
 	});
 
@@ -586,9 +581,10 @@ export function createMenuBuilder(opts: _MenuBuilderOptions) {
 		const value = overridable(valueWritable, args.onValueChange);
 
 		const radioGroup = makeElement(name('radio-group'), {
-			returned: () => ({
-				role: 'group',
-			}),
+			returned: () =>
+				({
+					role: 'group',
+				} as const),
 		});
 
 		const radioItemDefaults = {
@@ -611,7 +607,7 @@ export function createMenuBuilder(opts: _MenuBuilderOptions) {
 						'data-value': itemValue,
 						'data-orientation': 'vertical',
 						tabindex: -1,
-					};
+					} as const;
 				};
 			},
 			action: (node: HTMLElement): MeltActionReturn<MenuEvents['radioItem']> => {
@@ -792,9 +788,10 @@ export function createMenuBuilder(opts: _MenuBuilderOptions) {
 						const activeTrigger = subActiveTrigger.get();
 						if (!activeTrigger) return;
 						tick().then(() => {
+							unsubPopper();
 							const parentMenuEl = getParentMenu(activeTrigger);
 
-							const popper = usePopper(node, {
+							unsubPopper = usePopper(node, {
 								anchorElement: activeTrigger,
 								open: subOpen,
 								options: {
@@ -804,11 +801,7 @@ export function createMenuBuilder(opts: _MenuBuilderOptions) {
 									focusTrap: null,
 									escapeKeydown: null,
 								},
-							});
-
-							if (popper && popper.destroy) {
-								unsubPopper = popper.destroy;
-							}
+							}).destroy;
 						});
 					}
 				);
@@ -1075,14 +1068,15 @@ export function createMenuBuilder(opts: _MenuBuilderOptions) {
 
 		const subArrow = makeElement(name('subarrow'), {
 			stores: arrowSize,
-			returned: ($arrowSize) => ({
-				'data-arrow': true,
-				style: styleToString({
-					position: 'absolute',
-					width: `var(--arrow-size, ${$arrowSize}px)`,
-					height: `var(--arrow-size, ${$arrowSize}px)`,
-				}),
-			}),
+			returned: ($arrowSize) =>
+				({
+					'data-arrow': true,
+					style: styleToString({
+						position: 'absolute',
+						width: `var(--arrow-size, ${$arrowSize}px)`,
+						height: `var(--arrow-size, ${$arrowSize}px)`,
+					}),
+				} as const),
 		});
 
 		/* -------------------------------------------------------------------------------------------------
diff --git a/src/lib/builders/menubar/create.ts b/src/lib/builders/menubar/create.ts
index 0eaff1f0..9777b3cb 100644
--- a/src/lib/builders/menubar/create.ts
+++ b/src/lib/builders/menubar/create.ts
@@ -163,7 +163,8 @@ export function createMenubar(props?: CreateMenubarProps) {
 						if (!($rootOpen && $rootActiveTrigger)) return;
 
 						tick().then(() => {
-							const popper = usePopper(node, {
+							unsubPopper();
+							unsubPopper = usePopper(node, {
 								anchorElement: $rootActiveTrigger,
 								open: rootOpen,
 								options: {
@@ -186,11 +187,7 @@ export function createMenubar(props?: CreateMenubarProps) {
 										open: $rootOpen,
 									},
 								},
-							});
-
-							if (popper && popper.destroy) {
-								unsubPopper = popper.destroy;
-							}
+							}).destroy;
 						});
 					}
 				);
diff --git a/src/lib/builders/pagination/create.ts b/src/lib/builders/pagination/create.ts
index 0fc758b9..f5952823 100644
--- a/src/lib/builders/pagination/create.ts
+++ b/src/lib/builders/pagination/create.ts
@@ -46,9 +46,10 @@ export function createPagination(props: CreatePaginationProps) {
 	});
 
 	const root = makeElement(name(), {
-		returned: () => ({
-			'data-scope': 'pagination',
-		}),
+		returned: () =>
+			({
+				'data-scope': 'pagination',
+			} as const),
 	});
 
 	const pages = derived([page, totalPages, siblingCount], ([$page, $totalPages, $siblingCount]) => {
@@ -99,7 +100,7 @@ export function createPagination(props: CreatePaginationProps) {
 					'aria-label': `Page ${pageItem.value}`,
 					'data-value': pageItem.value,
 					'data-selected': pageItem.value === $page ? '' : undefined,
-				};
+				} as const;
 			};
 		},
 		action: (node: HTMLElement): MeltActionReturn<PaginationEvents['pageTrigger']> => {
diff --git a/src/lib/builders/pin-input/create.ts b/src/lib/builders/pin-input/create.ts
index ee780cff..4e8f774d 100644
--- a/src/lib/builders/pin-input/create.ts
+++ b/src/lib/builders/pin-input/create.ts
@@ -68,7 +68,7 @@ export function createPinInput(props?: CreatePinInputProps) {
 			return {
 				id: $rootId,
 				'data-complete': $value.length && $value.every((v) => v.length > 0) ? '' : undefined,
-			};
+			} as const;
 		},
 	});
 
@@ -98,7 +98,7 @@ export function createPinInput(props?: CreatePinInputProps) {
 					disabled: disabledAttr($disabled),
 					type: $type,
 					value: currValue,
-				};
+				} as const;
 			};
 		},
 		action: (node: HTMLInputElement): MeltActionReturn<PinInputEvents['input']> => {
diff --git a/src/lib/builders/popover/create.ts b/src/lib/builders/popover/create.ts
index 9dcae99f..ddc8ef49 100644
--- a/src/lib/builders/popover/create.ts
+++ b/src/lib/builders/popover/create.ts
@@ -17,9 +17,9 @@ import {
 	removeScroll,
 	styleToString,
 	toWritableStores,
-	sleep,
 	portalAttr,
 	generateIds,
+	withGet,
 } from '$lib/internal/helpers/index.js';
 
 import {
@@ -80,7 +80,7 @@ export function createPopover(args?: CreatePopoverProps) {
 	const openWritable = withDefaults.open ?? writable(withDefaults.defaultOpen);
 	const open = overridable(openWritable, withDefaults?.onOpenChange);
 
-	const activeTrigger = writable<HTMLElement | null>(null);
+	const activeTrigger = withGet.writable<HTMLElement | null>(null);
 
 	const ids = toWritableStores({ ...generateIds(popoverIdParts), ...withDefaults.ids });
 
@@ -88,8 +88,7 @@ export function createPopover(args?: CreatePopoverProps) {
 		activeTrigger.set(document.getElementById(ids.trigger.get()));
 	});
 
-	async function handleClose() {
-		await sleep(0);
+	function handleClose() {
 		open.set(false);
 		const triggerEl = document.getElementById(ids.trigger.get());
 		handleFocus({ prop: closeFocus.get(), defaultEl: triggerEl });
@@ -109,7 +108,7 @@ export function createPopover(args?: CreatePopoverProps) {
 				id: $contentId,
 				'data-state': $isVisible ? 'open' : 'closed',
 				'data-portal': portalAttr($portal),
-			};
+			} as const;
 		},
 		action: (node: HTMLElement) => {
 			let unsubPopper = noop;
@@ -136,38 +135,38 @@ export function createPopover(args?: CreatePopoverProps) {
 					unsubPopper();
 					if (!$isVisible || !$activeTrigger) return;
 
-					const popper = usePopper(node, {
-						anchorElement: $activeTrigger,
-						open,
-						options: {
-							floating: $positioning,
-							focusTrap: $disableFocusTrap
-								? null
-								: {
-										returnFocusOnDeactivate: false,
-										clickOutsideDeactivates: true,
-										escapeDeactivates: true,
-								  },
-							modal: {
-								shouldCloseOnInteractOutside: shouldCloseOnInteractOutside,
-								onClose: handleClose,
-								open: $isVisible,
-								closeOnInteractOutside: $closeOnOutsideClick,
+					tick().then(() => {
+						unsubPopper();
+						unsubPopper = usePopper(node, {
+							anchorElement: $activeTrigger,
+							open,
+							options: {
+								floating: $positioning,
+								focusTrap: $disableFocusTrap
+									? null
+									: {
+											returnFocusOnDeactivate: false,
+											clickOutsideDeactivates: $closeOnOutsideClick,
+											allowOutsideClick: true,
+											escapeDeactivates: $closeOnEscape,
+									  },
+								modal: {
+									shouldCloseOnInteractOutside: shouldCloseOnInteractOutside,
+									onClose: handleClose,
+									open: $isVisible,
+									closeOnInteractOutside: $closeOnOutsideClick,
+								},
+								escapeKeydown: $closeOnEscape
+									? {
+											handler: () => {
+												handleClose();
+											},
+									  }
+									: null,
+								portal: getPortalDestination(node, $portal),
 							},
-							escapeKeydown: $closeOnEscape
-								? {
-										handler: () => {
-											handleClose();
-										},
-								  }
-								: null,
-							portal: getPortalDestination(node, $portal),
-						},
+						}).destroy;
 					});
-
-					if (popper && popper.destroy) {
-						unsubPopper = popper.destroy;
-					}
 				}
 			);
 
@@ -184,7 +183,7 @@ export function createPopover(args?: CreatePopoverProps) {
 		open.update((prev) => {
 			return !prev;
 		});
-		if (triggerEl) {
+		if (triggerEl && triggerEl !== activeTrigger.get()) {
 			activeTrigger.set(triggerEl);
 		}
 	}
@@ -245,6 +244,8 @@ export function createPopover(args?: CreatePopoverProps) {
 		},
 		action: (node: HTMLElement) => {
 			let unsubEscapeKeydown = noop;
+			let unsubDerived = noop;
+			let unsubPortal = noop;
 
 			if (closeOnEscape.get()) {
 				const escapeKeydown = useEscapeKeydown(node, {
@@ -257,21 +258,18 @@ export function createPopover(args?: CreatePopoverProps) {
 				}
 			}
 
-			const unsubPortal = effect([portal], ([$portal]) => {
-				if ($portal === null) return noop;
+			unsubDerived = effect([portal], ([$portal]) => {
+				unsubPortal();
+				if ($portal === null) return;
 				const portalDestination = getPortalDestination(node, $portal);
-				if (portalDestination === null) return noop;
-				const portalAction = usePortal(node, portalDestination);
-				if (portalAction && portalAction.destroy) {
-					return portalAction.destroy;
-				} else {
-					return noop;
-				}
+				if (portalDestination === null) return;
+				unsubPortal = usePortal(node, portalDestination).destroy;
 			});
 
 			return {
 				destroy() {
 					unsubEscapeKeydown();
+					unsubDerived();
 					unsubPortal();
 				},
 			};
@@ -280,14 +278,15 @@ export function createPopover(args?: CreatePopoverProps) {
 
 	const arrow = makeElement(name('arrow'), {
 		stores: arrowSize,
-		returned: ($arrowSize) => ({
-			'data-arrow': true,
-			style: styleToString({
-				position: 'absolute',
-				width: `var(--arrow-size, ${$arrowSize}px)`,
-				height: `var(--arrow-size, ${$arrowSize}px)`,
-			}),
-		}),
+		returned: ($arrowSize) =>
+			({
+				'data-arrow': true,
+				style: styleToString({
+					position: 'absolute',
+					width: `var(--arrow-size, ${$arrowSize}px)`,
+					height: `var(--arrow-size, ${$arrowSize}px)`,
+				}),
+			} as const),
 	});
 
 	const close = makeElement(name('close'), {
diff --git a/src/lib/builders/progress/create.ts b/src/lib/builders/progress/create.ts
index 5c3f725f..3d61d918 100644
--- a/src/lib/builders/progress/create.ts
+++ b/src/lib/builders/progress/create.ts
@@ -37,7 +37,7 @@ export const createProgress = (props?: CreateProgressProps) => {
 				'data-value': $value,
 				'data-state': $value === null ? 'indeterminate' : $value === $max ? 'complete' : 'loading',
 				'data-max': $max,
-			};
+			} as const;
 		},
 	});
 
diff --git a/src/lib/builders/range-calendar/create.ts b/src/lib/builders/range-calendar/create.ts
index 9ba83009..1353d0b5 100644
--- a/src/lib/builders/range-calendar/create.ts
+++ b/src/lib/builders/range-calendar/create.ts
@@ -285,7 +285,7 @@ export function createRangeCalendar<T extends DateValue = DateValue>(
 				'data-invalid': $isInvalid ? '' : undefined,
 				'data-disabled': $disabled ? '' : undefined,
 				'data-readonly': $readonly ? '' : undefined,
-			};
+			} as const;
 		},
 		action: (node: HTMLElement): MeltActionReturn<RangeCalendarEvents['calendar']> => {
 			/**
@@ -312,20 +312,21 @@ export function createRangeCalendar<T extends DateValue = DateValue>(
 			return {
 				'aria-hidden': true,
 				'data-disabled': $disabled ? '' : undefined,
-			};
+			} as const;
 		},
 	});
 
 	const grid = makeElement(name('grid'), {
 		stores: [readonly, disabled],
-		returned: ([$readonly, $disabled]) => ({
-			tabindex: -1,
-			role: 'grid',
-			'aria-readonly': $readonly ? ('true' as const) : undefined,
-			'aria-disabled': $disabled ? ('true' as const) : undefined,
-			'data-readonly': $readonly ? '' : undefined,
-			'data-disabled': $disabled ? '' : undefined,
-		}),
+		returned: ([$readonly, $disabled]) =>
+			({
+				tabindex: -1,
+				role: 'grid',
+				'aria-readonly': $readonly ? 'true' : undefined,
+				'aria-disabled': $disabled ? 'true' : undefined,
+				'data-readonly': $readonly ? '' : undefined,
+				'data-disabled': $disabled ? '' : undefined,
+			} as const),
 	});
 
 	const prevButton = makeElement(name('prevButton'), {
@@ -336,10 +337,10 @@ export function createRangeCalendar<T extends DateValue = DateValue>(
 				role: 'button',
 				type: 'button' as const,
 				'aria-label': 'Previous',
-				'aria-disabled': disabled ? ('true' as const) : undefined,
+				'aria-disabled': disabled ? 'true' : undefined,
 				disabled: disabled ? true : undefined,
 				'data-disabled': disabled ? '' : undefined,
-			};
+			} as const;
 		},
 		action: (node: HTMLElement): MeltActionReturn<RangeCalendarEvents['prevButton']> => {
 			const unsub = executeCallbacks(
@@ -361,10 +362,10 @@ export function createRangeCalendar<T extends DateValue = DateValue>(
 				role: 'button',
 				type: 'button' as const,
 				'aria-label': 'Next',
-				'aria-disabled': disabled ? ('true' as const) : undefined,
+				'aria-disabled': disabled ? 'true' : undefined,
 				disabled: disabled ? true : undefined,
 				'data-disabled': disabled ? '' : undefined,
-			};
+			} as const;
 		},
 		action: (node: HTMLElement): MeltActionReturn<RangeCalendarEvents['nextButton']> => {
 			const unsub = executeCallbacks(
@@ -545,20 +546,49 @@ export function createRangeCalendar<T extends DateValue = DateValue>(
 	 * Updates the displayed months based on changes in the placeholder value,
 	 * which determines the months to show in the calendar.
 	 */
-	effect(
-		[placeholder, weekStartsOn, locale, fixedWeeks, numberOfMonths],
-		([$placeholder, $weekStartsOn, $locale, $fixedWeeks, $numberOfMonths]) => {
-			if (!isBrowser || !$placeholder) return;
+	effect([placeholder], ([$placeholder]) => {
+		if (!isBrowser || !$placeholder) return;
 
-			const $visibleMonths = visibleMonths.get();
+		const $visibleMonths = visibleMonths.get();
 
-			/**
-			 * If the placeholder's month is already in the visible months,
-			 * we don't need to do anything.
-			 */
-			if ($visibleMonths.some((month) => isSameMonth(month, $placeholder))) {
-				return;
-			}
+		/**
+		 * If the placeholder's month is already in the visible months,
+		 * we don't need to do anything.
+		 */
+		if ($visibleMonths.some((month) => isSameMonth(month, $placeholder))) {
+			return;
+		}
+
+		const $weekStartsOn = weekStartsOn.get();
+		const $locale = locale.get();
+		const $fixedWeeks = fixedWeeks.get();
+		const $numberOfMonths = numberOfMonths.get();
+
+		const defaultMonthProps = {
+			weekStartsOn: $weekStartsOn,
+			locale: $locale,
+			fixedWeeks: $fixedWeeks,
+			numberOfMonths: $numberOfMonths,
+		};
+
+		months.set(
+			createMonths({
+				...defaultMonthProps,
+				dateObj: $placeholder,
+			})
+		);
+	});
+
+	/**
+	 * Updates the displayed months based on changes in the options values,
+	 * which determines the months to show in the calendar.
+	 */
+	effect(
+		[weekStartsOn, locale, fixedWeeks, numberOfMonths],
+		([$weekStartsOn, $locale, $fixedWeeks, $numberOfMonths]) => {
+			const $placeholder = placeholder.get();
+
+			if (!isBrowser || !$placeholder) return;
 
 			const defaultMonthProps = {
 				weekStartsOn: $weekStartsOn,
diff --git a/src/lib/builders/separator/create.ts b/src/lib/builders/separator/create.ts
index d4d2aeab..c2133db1 100644
--- a/src/lib/builders/separator/create.ts
+++ b/src/lib/builders/separator/create.ts
@@ -21,7 +21,7 @@ export const createSeparator = (props?: CreateSeparatorProps) => {
 				'aria-orientation': ariaOrientation,
 				'aria-hidden': $decorative,
 				'data-orientation': $orientation,
-			};
+			} as const;
 		},
 	});
 
diff --git a/src/lib/builders/slider/create.ts b/src/lib/builders/slider/create.ts
index b2fa5e22..fa647551 100644
--- a/src/lib/builders/slider/create.ts
+++ b/src/lib/builders/slider/create.ts
@@ -125,7 +125,7 @@ export const createSlider = (props?: CreateSliderProps) => {
 					: `touch-action: ${$orientation === 'horizontal' ? 'pan-y' : 'pan-x'}`,
 
 				'data-melt-id': meltIds.root,
-			};
+			} as const;
 		},
 	});
 
@@ -164,7 +164,7 @@ export const createSlider = (props?: CreateSliderProps) => {
 
 			return {
 				style: styleToString(style),
-			};
+			} as const;
 		},
 	});
 
@@ -394,7 +394,7 @@ export const createSlider = (props?: CreateSliderProps) => {
 					'data-bounded': bounded ? true : undefined,
 					'data-value': tickValue,
 					style: styleToString(style),
-				};
+				} as const;
 			});
 		},
 	});
diff --git a/src/lib/builders/switch/create.ts b/src/lib/builders/switch/create.ts
index 4d1aa06e..74724849 100644
--- a/src/lib/builders/switch/create.ts
+++ b/src/lib/builders/switch/create.ts
@@ -74,7 +74,7 @@ export function createSwitch(props?: CreateSwitchProps) {
 		stores: [checked, nameStore, required, disabled, value],
 		returned: ([$checked, $name, $required, $disabled, $value]) => {
 			return {
-				type: 'checkbox' as const,
+				type: 'checkbox',
 				'aria-hidden': true,
 				hidden: true,
 				tabindex: -1,
diff --git a/src/lib/builders/table-of-contents/create.ts b/src/lib/builders/table-of-contents/create.ts
index 043d3d13..978d7345 100644
--- a/src/lib/builders/table-of-contents/create.ts
+++ b/src/lib/builders/table-of-contents/create.ts
@@ -355,7 +355,7 @@ export function createTableOfContents(args: CreateTableOfContentsArgs) {
 				return {
 					'data-id': id,
 					'data-active': active ? '' : undefined,
-				};
+				} as const;
 			};
 		},
 		action: (node: HTMLAnchorElement) => {
diff --git a/src/lib/builders/tabs/create.ts b/src/lib/builders/tabs/create.ts
index 8dac2383..96cdb5d7 100644
--- a/src/lib/builders/tabs/create.ts
+++ b/src/lib/builders/tabs/create.ts
@@ -50,7 +50,7 @@ export function createTabs(props?: CreateTabsProps) {
 		returned: ($orientation) => {
 			return {
 				'data-orientation': $orientation,
-			};
+			} as const;
 		},
 	});
 
@@ -62,7 +62,7 @@ export function createTabs(props?: CreateTabsProps) {
 				role: 'tablist',
 				'aria-orientation': $orientation,
 				'data-orientation': $orientation,
-			};
+			} as const;
 		},
 	});
 
@@ -90,7 +90,7 @@ export function createTabs(props?: CreateTabsProps) {
 				const isActive = sourceOfTruth === tabValue;
 
 				return {
-					type: 'button' as const,
+					type: 'button',
 					role: 'tab',
 					'data-state': isActive ? 'active' : 'inactive',
 					tabindex: isActive ? 0 : -1,
@@ -98,7 +98,7 @@ export function createTabs(props?: CreateTabsProps) {
 					'data-orientation': $orientation,
 					'data-disabled': disabledAttr(disabled),
 					disabled: disabledAttr(disabled),
-				};
+				} as const;
 			};
 		},
 		action: (node: HTMLElement): MeltActionReturn<TabsEvents['trigger']> => {
@@ -194,7 +194,7 @@ export function createTabs(props?: CreateTabsProps) {
 						? undefined
 						: true,
 					tabindex: 0,
-				};
+				} as const;
 			};
 		},
 	});
diff --git a/src/lib/builders/tags-input/create.ts b/src/lib/builders/tags-input/create.ts
index 12c1c6b3..5e5127f0 100644
--- a/src/lib/builders/tags-input/create.ts
+++ b/src/lib/builders/tags-input/create.ts
@@ -262,7 +262,7 @@ export function createTagsInput(props?: CreateTagsInputProps) {
 				'data-disabled': disabledAttr($disabled),
 				disabled: disabledAttr($disabled),
 				placeholder: $placeholder,
-			};
+			} as const;
 		},
 		action: (node: HTMLInputElement): MeltActionReturn<TagsInputEvents['input']> => {
 			const getTagsInfo = (id: string) => {
@@ -497,7 +497,7 @@ export function createTagsInput(props?: CreateTagsInputProps) {
 								margin: 0,
 						  })
 						: undefined,
-				};
+				} as const;
 			};
 		},
 		action: (node: HTMLDivElement): MeltActionReturn<TagsInputEvents['tag']> => {
@@ -583,7 +583,7 @@ export function createTagsInput(props?: CreateTagsInputProps) {
 					'data-disabled': disabledAttr(disabled),
 					disabled: disabledAttr(disabled),
 					tabindex: -1,
-				};
+				} as const;
 			};
 		},
 		action: (node: HTMLElement): MeltActionReturn<TagsInputEvents['deleteTrigger']> => {
@@ -638,7 +638,7 @@ export function createTagsInput(props?: CreateTagsInputProps) {
 								margin: 0,
 						  })
 						: undefined,
-				};
+				} as const;
 			};
 		},
 		action: (node: HTMLElement): MeltActionReturn<TagsInputEvents['edit']> => {
diff --git a/src/lib/builders/toast/create.ts b/src/lib/builders/toast/create.ts
index fd7d104a..2576e73a 100644
--- a/src/lib/builders/toast/create.ts
+++ b/src/lib/builders/toast/create.ts
@@ -111,9 +111,9 @@ export function createToaster<T = object>(props?: CreateToasterProps) {
 					role: 'alert',
 					'aria-describedby': toast.ids.description,
 					'aria-labelledby': toast.ids.title,
-					'aria-live': toast.type === 'foreground' ? ('assertive' as const) : ('polite' as const),
+					'aria-live': toast.type === 'foreground' ? 'assertive' : 'polite',
 					tabindex: -1,
-				};
+				} as const;
 			};
 		},
 		action: (node: HTMLElement): MeltActionReturn<ToastEvents['content']> => {
@@ -170,7 +170,7 @@ export function createToaster<T = object>(props?: CreateToasterProps) {
 				if (!toast) return null;
 				return {
 					id: toast.ids.title,
-				};
+				} as const;
 			};
 		},
 	});
@@ -184,17 +184,18 @@ export function createToaster<T = object>(props?: CreateToasterProps) {
 
 				return {
 					id: toast.ids.description,
-				};
+				} as const;
 			};
 		},
 	});
 
 	const close = makeElement(name('close'), {
 		returned: () => {
-			return (id: string) => ({
-				type: 'button' as const,
-				'data-id': id,
-			});
+			return (id: string) =>
+				({
+					type: 'button',
+					'data-id': id,
+				} as const);
 		},
 		action: (node: HTMLElement): MeltActionReturn<ToastEvents['close']> => {
 			function handleClose() {
diff --git a/src/lib/builders/toolbar/create.ts b/src/lib/builders/toolbar/create.ts
index 051ab1c4..e810e9eb 100644
--- a/src/lib/builders/toolbar/create.ts
+++ b/src/lib/builders/toolbar/create.ts
@@ -39,7 +39,7 @@ export const createToolbar = (props?: CreateToolbarProps) => {
 			return {
 				role: 'toolbar',
 				'data-orientation': $orientation,
-			};
+			} as const;
 		},
 	});
 
diff --git a/src/lib/builders/tooltip/create.ts b/src/lib/builders/tooltip/create.ts
index cd20300d..48e101ee 100644
--- a/src/lib/builders/tooltip/create.ts
+++ b/src/lib/builders/tooltip/create.ts
@@ -19,7 +19,6 @@ import {
 	styleToString,
 	toWritableStores,
 	removeUndefined,
-	sleep,
 	portalAttr,
 } from '$lib/internal/helpers/index.js';
 
@@ -29,6 +28,7 @@ import { derived, writable, type Writable } from 'svelte/store';
 import { generateIds } from '../../internal/helpers/id.js';
 import type { TooltipEvents } from './events.js';
 import type { CreateTooltipProps } from './types.js';
+import { tick } from 'svelte';
 
 const defaults = {
 	positioning: {
@@ -142,7 +142,7 @@ export function createTooltip(props?: CreateTooltipProps) {
 				'aria-describedby': $contentId,
 				id: $triggerId,
 				'data-state': $open ? 'open' : 'closed',
-			};
+			} as const;
 		},
 		action: (node: HTMLElement): MeltActionReturn<TooltipEvents['trigger']> => {
 			const keydownHandler = (e: KeyboardEvent) => {
@@ -182,10 +182,7 @@ export function createTooltip(props?: CreateTooltipProps) {
 					if (clickedTrigger) return;
 					openTooltip('focus');
 				}),
-				addMeltEventListener(node, 'blur', async () => {
-					await sleep(0);
-					closeTooltip(true);
-				}),
+				addMeltEventListener(node, 'blur', () => closeTooltip(true)),
 				addMeltEventListener(node, 'keydown', keydownHandler),
 				addEventListener(document, 'keydown', keydownHandler)
 			);
@@ -207,7 +204,7 @@ export function createTooltip(props?: CreateTooltipProps) {
 				id: $contentId,
 				'data-portal': portalAttr($portal),
 				'data-state': $open ? 'open' : 'closed',
-			});
+			} as const);
 		},
 		action: (node: HTMLElement): MeltActionReturn<TooltipEvents['content']> => {
 			let unsubFloating = noop;
@@ -216,26 +213,18 @@ export function createTooltip(props?: CreateTooltipProps) {
 			const unsubDerived = effect(
 				[isVisible, positioning, portal],
 				([$isVisible, $positioning, $portal]) => {
+					unsubPortal();
+					unsubFloating();
 					const triggerEl = getEl('trigger');
-					if (!$isVisible || !triggerEl) {
-						unsubPortal();
-						unsubFloating();
-						return;
-					}
+					if (!$isVisible || !triggerEl) return;
 
-					const floatingReturn = useFloating(triggerEl, node, $positioning);
-					unsubFloating = floatingReturn.destroy;
-					if ($portal === null) {
+					tick().then(() => {
 						unsubPortal();
-						return;
-					}
-					const portalDest = getPortalDestination(node, $portal);
-					if (portalDest) {
-						const portalReturn = usePortal(node, portalDest);
-						if (portalReturn && portalReturn.destroy) {
-							unsubPortal = portalReturn.destroy;
-						}
-					}
+						unsubFloating();
+						const portalDest = getPortalDestination(node, $portal);
+						if (portalDest) unsubPortal = usePortal(node, portalDest).destroy;
+						unsubFloating = useFloating(triggerEl, node, $positioning).destroy;
+					});
 				}
 			);
 
@@ -272,14 +261,15 @@ export function createTooltip(props?: CreateTooltipProps) {
 
 	const arrow = makeElement(name('arrow'), {
 		stores: arrowSize,
-		returned: ($arrowSize) => ({
-			'data-arrow': true,
-			style: styleToString({
-				position: 'absolute',
-				width: `var(--arrow-size, ${$arrowSize}px)`,
-				height: `var(--arrow-size, ${$arrowSize}px)`,
-			}),
-		}),
+		returned: ($arrowSize) =>
+			({
+				'data-arrow': true,
+				style: styleToString({
+					position: 'absolute',
+					width: `var(--arrow-size, ${$arrowSize}px)`,
+					height: `var(--arrow-size, ${$arrowSize}px)`,
+				}),
+			} as const),
 	});
 
 	let isMouseInTooltipArea = false;
diff --git a/src/lib/builders/tree/create.ts b/src/lib/builders/tree/create.ts
index d7bacbb2..2194ffe0 100644
--- a/src/lib/builders/tree/create.ts
+++ b/src/lib/builders/tree/create.ts
@@ -96,7 +96,7 @@ export function createTreeView(args?: CreateTreeViewProps) {
 					'data-id': id,
 					tabindex,
 					'aria-expanded': hasChildren ? $expanded.includes(id) : undefined,
-				};
+				} as const;
 			};
 		},
 		action: (node: HTMLElement): MeltActionReturn<TreeEvents['item']> => {
@@ -252,14 +252,15 @@ export function createTreeView(args?: CreateTreeViewProps) {
 	const group = makeElement(name('group'), {
 		stores: [expanded],
 		returned: ([$expanded]) => {
-			return (opts: { id: string }) => ({
-				role: 'group',
-				'data-group-id': opts.id,
-				hidden: !forceVisible && !$expanded.includes(opts.id) ? true : undefined,
-				style: styleToString({
-					display: !forceVisible && !$expanded.includes(opts.id) ? 'none' : undefined,
-				}),
-			});
+			return (opts: { id: string }) =>
+				({
+					role: 'group',
+					'data-group-id': opts.id,
+					hidden: !forceVisible && !$expanded.includes(opts.id) ? true : undefined,
+					style: styleToString({
+						display: !forceVisible && !$expanded.includes(opts.id) ? 'none' : undefined,
+					}),
+				} as const);
 		},
 	});
 
diff --git a/src/lib/internal/actions/escape-keydown/action.ts b/src/lib/internal/actions/escape-keydown/action.ts
index 4181b555..04c6190c 100644
--- a/src/lib/internal/actions/escape-keydown/action.ts
+++ b/src/lib/internal/actions/escape-keydown/action.ts
@@ -3,6 +3,7 @@ import { isFunction, isHTMLElement, isReadable } from '$lib/internal/helpers/is.
 import { get, readable, type Readable } from 'svelte/store';
 import { effect, executeCallbacks, kbd, noop } from '../../helpers/index.js';
 import type { EscapeKeydownConfig } from './types.js';
+import type { Action } from 'svelte/action';
 
 /**
  * Creates a readable store that tracks the latest Escape Keydown that occurred on the document.
@@ -35,7 +36,7 @@ const documentEscapeKeyStore = readable<KeyboardEvent | undefined>(
 	}
 );
 
-export const useEscapeKeydown = (node: HTMLElement, config: EscapeKeydownConfig = {}) => {
+export const useEscapeKeydown = ((node, config = {}) => {
 	let unsub = noop;
 	function update(config: EscapeKeydownConfig = {}) {
 		unsub();
@@ -96,4 +97,4 @@ export const useEscapeKeydown = (node: HTMLElement, config: EscapeKeydownConfig
 			unsub();
 		},
 	};
-};
+}) satisfies Action<HTMLElement, EscapeKeydownConfig>;
diff --git a/src/lib/internal/actions/floating/action.ts b/src/lib/internal/actions/floating/action.ts
index a1d34801..4847a13e 100644
--- a/src/lib/internal/actions/floating/action.ts
+++ b/src/lib/internal/actions/floating/action.ts
@@ -14,7 +14,7 @@ import {
 } from '@floating-ui/dom';
 import type { FloatingConfig } from './types.js';
 import { isHTMLElement, noop } from '$lib/internal/helpers/index.js';
-import type { VirtualElement } from '@floating-ui/core';
+import type { Placement, VirtualElement } from '@floating-ui/core';
 
 const defaultConfig = {
 	strategy: 'absolute',
@@ -32,6 +32,12 @@ const ARROW_TRANSFORM = {
 	right: 'rotate(315deg)',
 };
 
+const SIDE_OPTIONS = ['top', 'right', 'bottom', 'left'] as const;
+const ALIGN_OPTIONS = ['start', 'center', 'end'] as const;
+
+type Side = (typeof SIDE_OPTIONS)[number];
+type Align = (typeof ALIGN_OPTIONS)[number];
+
 export function useFloating(
 	reference: HTMLElement | VirtualElement | undefined,
 	floating: HTMLElement | undefined,
@@ -100,6 +106,9 @@ export function useFloating(
 
 	function compute() {
 		if (!reference || !floating) return;
+		// if the reference is no longer in the document (e.g. it was removed), ignore it
+		if (isHTMLElement(reference) && !reference.ownerDocument.documentElement.contains(reference))
+			return;
 		const { placement, strategy } = options;
 
 		computePosition(reference, floating, {
@@ -110,6 +119,13 @@ export function useFloating(
 			const x = Math.round(data.x);
 			const y = Math.round(data.y);
 
+			// get the chosen side and align from the placement to apply as attributes
+			// to the floating element and arrow
+			const [side, align] = getSideAndAlignFromPlacement(data.placement);
+
+			floating.setAttribute('data-side', side);
+			floating.setAttribute('data-align', align);
+
 			Object.assign(floating.style, {
 				position: options.strategy,
 				top: `${y}px`,
@@ -121,6 +137,8 @@ export function useFloating(
 
 				const dir = data.placement.split('-')[0] as 'top' | 'bottom' | 'left' | 'right';
 
+				arrowEl.setAttribute('data-side', dir);
+
 				Object.assign(arrowEl.style, {
 					position: 'absolute',
 					left: x != null ? `${x}px` : '',
@@ -145,3 +163,8 @@ export function useFloating(
 		destroy: autoUpdate(reference, floating, compute),
 	};
 }
+
+function getSideAndAlignFromPlacement(placement: Placement) {
+	const [side, align = 'center'] = placement.split('-');
+	return [side as Side, align as Align] as const;
+}
diff --git a/src/lib/internal/actions/focus-trap/action.ts b/src/lib/internal/actions/focus-trap/action.ts
index 4003c4f8..8cd1e7f2 100644
--- a/src/lib/internal/actions/focus-trap/action.ts
+++ b/src/lib/internal/actions/focus-trap/action.ts
@@ -7,7 +7,7 @@ import type { FocusTrapConfig, FocusTrapReturn } from './types.js';
 import { writable, readonly } from 'svelte/store';
 import { createFocusTrap as _createFocusTrap } from 'focus-trap';
 
-export function createFocusTrap(config: FocusTrapConfig = {}): FocusTrapReturn {
+export function createFocusTrap(config: FocusTrapConfig = {}) {
 	let trap: undefined | FocusTrap;
 
 	const { immediate, ...focusTrapOptions } = config;
@@ -66,5 +66,5 @@ export function createFocusTrap(config: FocusTrapConfig = {}): FocusTrapReturn {
 		deactivate,
 		pause,
 		unpause,
-	};
+	} satisfies FocusTrapReturn;
 }
diff --git a/src/lib/internal/actions/interact-outside/action.ts b/src/lib/internal/actions/interact-outside/action.ts
index 4fcdbb2d..28638d38 100644
--- a/src/lib/internal/actions/interact-outside/action.ts
+++ b/src/lib/internal/actions/interact-outside/action.ts
@@ -5,9 +5,11 @@ import {
 	noop,
 } from '$lib/internal/helpers/index.js';
 import type { InteractOutsideConfig, InteractOutsideEvent } from './types.js';
+import type { Action } from 'svelte/action';
 
-export function useInteractOutside(node: HTMLElement, config: InteractOutsideConfig) {
+export const useInteractOutside = ((node, config) => {
 	let unsub = noop;
+	let unsubClick = noop;
 
 	let isPointerDown = false;
 	let isPointerDownInside = false;
@@ -15,6 +17,7 @@ export function useInteractOutside(node: HTMLElement, config: InteractOutsideCon
 
 	function update(config: InteractOutsideConfig) {
 		unsub();
+		unsubClick();
 		const { onInteractOutside, onInteractOutsideStart, enabled } = config;
 
 		if (!enabled) return;
@@ -41,10 +44,29 @@ export function useInteractOutside(node: HTMLElement, config: InteractOutsideCon
 		// Use pointer events if available, otherwise use mouse/touch events
 		if (typeof PointerEvent !== 'undefined') {
 			const onPointerUp = (e: PointerEvent) => {
-				if (shouldTriggerInteractOutside(e)) {
-					triggerInteractOutside(e);
+				unsubClick();
+
+				const handler = (e: InteractOutsideEvent) => {
+					if (shouldTriggerInteractOutside(e)) {
+						triggerInteractOutside(e);
+					}
+					resetPointerState();
+				};
+
+				/**
+				 * On touch devices, we need to wait for a click event because browsers implement
+				 * a delay between the time the user stops touching the display and when the
+				 * browser executes the click event. Without waiting for the click event, the
+				 * browser may execute events on other elements that should have been prevented.
+				 */
+				if (e.pointerType === 'touch') {
+					unsubClick = addEventListener(documentObj, 'click', handler, {
+						capture: true,
+						once: true,
+					});
+					return;
 				}
-				resetPointerState();
+				handler(e);
 			};
 
 			unsub = executeCallbacks(
@@ -94,9 +116,12 @@ export function useInteractOutside(node: HTMLElement, config: InteractOutsideCon
 
 	return {
 		update,
-		destroy: unsub,
+		destroy() {
+			unsub();
+			unsubClick();
+		},
 	};
-}
+}) satisfies Action<HTMLElement, InteractOutsideConfig>;
 
 function isValidEvent(e: InteractOutsideEvent, node: HTMLElement): boolean {
 	if ('button' in e && e.button > 0) return false;
diff --git a/src/lib/internal/actions/modal/action.ts b/src/lib/internal/actions/modal/action.ts
index 5c4fb7b4..8cd452f3 100644
--- a/src/lib/internal/actions/modal/action.ts
+++ b/src/lib/internal/actions/modal/action.ts
@@ -2,10 +2,10 @@ import { isElement, last, noop, sleep } from '$lib/internal/helpers/index.js';
 import type { InteractOutsideEvent } from '../interact-outside/types.js';
 import { useInteractOutside } from '../index.js';
 import type { ModalConfig } from './types.js';
+import type { Action } from 'svelte/action';
 
 const visibleModals: Element[] = [];
-
-export function useModal(node: HTMLElement, config: ModalConfig) {
+export const useModal = ((node, config) => {
 	let unsubInteractOutside = noop;
 
 	function removeNodeFromVisibleModals() {
@@ -69,4 +69,4 @@ export function useModal(node: HTMLElement, config: ModalConfig) {
 			unsubInteractOutside();
 		},
 	};
-}
+}) satisfies Action<HTMLElement, ModalConfig>;
diff --git a/src/lib/internal/actions/popper/action.ts b/src/lib/internal/actions/popper/action.ts
index f17366a3..1b692c76 100644
--- a/src/lib/internal/actions/popper/action.ts
+++ b/src/lib/internal/actions/popper/action.ts
@@ -22,7 +22,7 @@ const defaultConfig = {
 	portal: 'body',
 } satisfies PopperConfig;
 
-export const usePopper: Action<HTMLElement, PopperArgs> = (popperElement, args) => {
+export const usePopper = ((popperElement, args) => {
 	popperElement.dataset.escapee = '';
 	const { anchorElement, open, options } = args as PopperArgs;
 	if (!anchorElement || !open || !options) {
@@ -34,10 +34,7 @@ export const usePopper: Action<HTMLElement, PopperArgs> = (popperElement, args)
 	const callbacks: Callback[] = [];
 
 	if (opts.portal !== null) {
-		const portal = usePortal(popperElement, opts.portal);
-		if (portal?.destroy) {
-			callbacks.push(portal.destroy);
-		}
+		callbacks.push(usePortal(popperElement, opts.portal).destroy);
 	}
 
 	callbacks.push(useFloating(anchorElement, popperElement, opts.floating).destroy);
@@ -53,11 +50,7 @@ export const usePopper: Action<HTMLElement, PopperArgs> = (popperElement, args)
 			...opts.focusTrap,
 		});
 
-		const usedFocusTrap = useFocusTrap(popperElement);
-
-		if (usedFocusTrap?.destroy) {
-			callbacks.push(usedFocusTrap.destroy);
-		}
+		callbacks.push(useFocusTrap(popperElement).destroy);
 	}
 
 	if (opts.modal !== null) {
@@ -103,4 +96,4 @@ export const usePopper: Action<HTMLElement, PopperArgs> = (popperElement, args)
 			unsubscribe();
 		},
 	};
-};
+}) satisfies Action<HTMLElement, PopperArgs>;
diff --git a/src/lib/internal/actions/portal.ts b/src/lib/internal/actions/portal.ts
index 50e0e3c6..f2581099 100644
--- a/src/lib/internal/actions/portal.ts
+++ b/src/lib/internal/actions/portal.ts
@@ -4,7 +4,7 @@ import { isHTMLElement, noop } from '$lib/internal/helpers/index.js';
 
 export type PortalConfig = string | HTMLElement | undefined;
 
-export const usePortal: Action<HTMLElement, PortalConfig> = (el, target = 'body') => {
+export const usePortal = ((el, target = 'body') => {
 	let targetEl;
 
 	if (!isHTMLElement(target) && typeof target !== 'string') {
@@ -47,4 +47,4 @@ export const usePortal: Action<HTMLElement, PortalConfig> = (el, target = 'body'
 		update,
 		destroy,
 	};
-};
+}) satisfies Action<HTMLElement, PortalConfig>;
diff --git a/src/lib/internal/helpers/attr.ts b/src/lib/internal/helpers/attr.ts
index 621863a9..69a6c053 100644
--- a/src/lib/internal/helpers/attr.ts
+++ b/src/lib/internal/helpers/attr.ts
@@ -24,7 +24,7 @@ export const hiddenInputAttrs = {
  */
 export function portalAttr(portal: string | HTMLElement | null | undefined) {
 	if (portal !== null) {
-		return portal;
+		return '';
 	}
 	return undefined;
 }


Test patch:
diff --git a/e2e/dialog.spec.ts b/e2e/dialog.spec.ts
new file mode 100644
index 00000000..e3f94dfc
--- /dev/null
+++ b/e2e/dialog.spec.ts
@@ -0,0 +1,74 @@
+import { test, expect, type Page, Locator } from '@playwright/test';
+import { jsAvailable } from './utils.js';
+
+const locators = {
+	trigger: '[data-melt-dialog-trigger]',
+	overlay: '[data-melt-dialog-overlay][data-state="open"]',
+	content: '[data-melt-dialog-content][data-state="open"]',
+};
+
+async function nav(page: Page) {
+	await page.goto('/docs/builders/dialog');
+	await jsAvailable(page);
+}
+
+test.describe.configure({ mode: 'parallel' });
+
+test.describe('dialog', () => {
+	test.beforeEach(async ({ page }) => {
+		await nav(page);
+	});
+
+	test.describe('touch device', () => {
+		test("doesn't leak events when tapping overlay", async ({ page }) => {
+			const trigger = page.locator(locators.trigger).first();
+			const content = page.locator(locators.content).first();
+			const viewCodeButton = page.getByLabel('View code').first();
+
+			await trigger.click();
+			await expect(content).toBeVisible();
+
+			const [centerX, centerY] = await getElementCenterPosition(viewCodeButton);
+
+			// Make sure "View Code" Button is not under the dialog, but under the overlay.
+			const isButtonUnderneathContent = await isPositionInsideElement(content, centerX, centerY);
+			expect(isButtonUnderneathContent).toBe(false);
+
+			// Tap the overlay at the position of the "View code" button
+			await page.tap(locators.overlay, { position: { x: centerX, y: centerY } });
+
+			await expect(content).not.toBeVisible();
+
+			// Verify the state of the "View Code" is "unchecked".
+			const viewCodeState = await viewCodeButton.getAttribute('data-state');
+			expect(viewCodeState).toBe('unchecked');
+		});
+	});
+});
+
+/**
+ * Retrieves the bounding box of an element and throws an error if `null`.
+ */
+const getBoundingBox = async (locator: Locator) => {
+	const bounding = await locator.boundingBox();
+	if (!bounding) throw new Error(`Failed to get position of '${locator}'`);
+	return bounding;
+};
+
+/**
+ * Retrieves the center position (x, y coordinates) of an element represented by a Locator.
+ */
+const getElementCenterPosition = async (locator: Locator) => {
+	const bounding = await getBoundingBox(locator);
+	return [bounding.x + bounding.width / 2, bounding.y + bounding.height / 2] as const;
+};
+
+/**
+ * Verifies an x, y position is within the boundaries of an element.
+ */
+const isPositionInsideElement = async (locator: Locator, x: number, y: number) => {
+	const bounding = await getBoundingBox(locator);
+	const isXValid = bounding.x <= x && x <= bounding.x + bounding.width;
+	const isYValid = bounding.y <= y && y <= bounding.y + bounding.height;
+	return isXValid && isYValid;
+};
diff --git a/e2e/dropdown.spec.ts b/e2e/dropdown.spec.ts
index c34dfe3d..8ac3433f 100644
--- a/e2e/dropdown.spec.ts
+++ b/e2e/dropdown.spec.ts
@@ -16,7 +16,7 @@ async function nav(page: Page) {
 
 test.describe.configure({ mode: 'parallel' });
 
-test.describe('menu', () => {
+test.describe.skip('menu', () => {
 	test.beforeEach(async ({ page }) => {
 		await nav(page);
 	});
@@ -40,7 +40,7 @@ test.describe('menu', () => {
 	}
 });
 
-test.describe('first menu item', () => {
+test.describe.skip('first menu item', () => {
 	test.beforeEach(async ({ page }) => {
 		await nav(page);
 	});
diff --git a/e2e/utils.ts b/e2e/utils.ts
index 93e98950..2c0888cc 100644
--- a/e2e/utils.ts
+++ b/e2e/utils.ts
@@ -1,5 +1,10 @@
 import { Page } from '@playwright/test';
 
 export const jsAvailable = async (page: Page) => {
+	if (process.env.CI) {
+		return await page.evaluate(() => {
+			return new Promise((resolve) => setTimeout(resolve, 0));
+		});
+	}
 	await page.waitForSelector('[data-browser]');
 };
diff --git a/src/tests/calendar/Calendar.spec.ts b/src/tests/calendar/Calendar.spec.ts
index 9cca7573..b00bc355 100644
--- a/src/tests/calendar/Calendar.spec.ts
+++ b/src/tests/calendar/Calendar.spec.ts
@@ -1,14 +1,14 @@
-import { testKbd as kbd } from '../utils.js';
+import type { CreateCalendarProps } from '$lib/builders/index.js';
+import { CalendarDate, CalendarDateTime, toZoned, type DateValue } from '@internationalized/date';
 import { render } from '@testing-library/svelte';
 import { userEvent } from '@testing-library/user-event';
 import { axe } from 'jest-axe';
-import { describe } from 'vitest';
-import CalendarTest from './CalendarTest.svelte';
-import { CalendarDate, CalendarDateTime, toZoned, type DateValue } from '@internationalized/date';
-import { writable } from 'svelte/store';
 import { tick } from 'svelte';
+import { writable } from 'svelte/store';
+import { describe } from 'vitest';
+import { testKbd as kbd } from '../utils.js';
 import CalendarMultiTest from './CalendarMultiTest.svelte';
-import type { CreateCalendarProps } from '$lib/builders/index.js';
+import CalendarTest from './CalendarTest.svelte';
 
 const calendarDate = new CalendarDate(1980, 1, 20);
 const calendarDateTime = new CalendarDateTime(1980, 1, 20, 12, 30, 0, 0);
@@ -679,6 +679,75 @@ describe('Calendar', () => {
 		}
 	});
 
+	test('dynamically change numberOfMonths option', async () => {
+		const { queryByTestId, getByTestId, user } = setup();
+
+		let grid0 = queryByTestId('grid-0');
+		let grid1 = queryByTestId('grid-1');
+		expect(grid0).toBeInTheDocument();
+		expect(grid1).toBeNull();
+
+		const numberOfMonthsButton = getByTestId('numberOfMonths');
+		await user.click(numberOfMonthsButton);
+
+		grid0 = queryByTestId('grid-0');
+		grid1 = queryByTestId('grid-1');
+		expect(grid0).toBeInTheDocument();
+		expect(grid1).toBeInTheDocument();
+	});
+
+	test('dynamically change weekStartsOn option', async () => {
+		const { getByTestId, user } = setup();
+
+		const weekDaysCopy = [...narrowWeekdays];
+
+		let weekdayElement = getByTestId(`weekdays`);
+
+		for (let i = 0; i < weekDaysCopy.length; i++) {
+			expect(weekdayElement.children[i]).toHaveTextContent(weekDaysCopy[i]);
+		}
+
+		const weekStartsOnButton = getByTestId('weekStartsOn');
+		await user.click(weekStartsOnButton);
+		const first = weekDaysCopy.shift();
+		if (first) {
+			weekDaysCopy.push(first);
+		}
+
+		weekdayElement = getByTestId(`weekdays`);
+		for (let i = 0; i < weekDaysCopy.length; i++) {
+			expect(weekdayElement.children[i]).toHaveTextContent(weekDaysCopy[i]);
+		}
+	});
+
+	test('dynamically change fixedWeeks option', async () => {
+		const { getByTestId, queryByTestId, user } = setup();
+
+		const nextButton = getByTestId('next-button');
+
+		while (queryByTestId('week-6') !== null) {
+			await user.click(nextButton);
+		}
+
+		const fixedWeeksButton = getByTestId('fixedWeeks');
+		await user.click(fixedWeeksButton);
+
+		expect(queryByTestId('week-6')).not.toBeNull();
+	});
+
+	test('dynamically changing the locale option also update weekStartsOn', async () => {
+		const { getByTestId, user } = setup();
+
+		let weekdayElement = getByTestId(`weekday-0`);
+		expect(weekdayElement).toHaveTextContent('S');
+
+		const localeButton = getByTestId('locale');
+		await user.click(localeButton);
+		weekdayElement = getByTestId(`weekday-0`);
+		// L is italian for Lunedì which is Monday (which is different from S which is Sunday)
+		expect(weekdayElement).toHaveTextContent('L');
+	});
+
 	test('custom ids are applied when provided', async () => {
 		const ids = {
 			accessibleHeading: 'id-heading',
diff --git a/src/tests/calendar/CalendarTest.svelte b/src/tests/calendar/CalendarTest.svelte
index 7159efac..81b5246f 100644
--- a/src/tests/calendar/CalendarTest.svelte
+++ b/src/tests/calendar/CalendarTest.svelte
@@ -30,7 +30,13 @@
 	const {
 		elements: { calendar, heading, grid, cell, prevButton, nextButton },
 		states: { value: insideValue, months, headingValue, weekdays },
-		options: { weekdayFormat: weekdayFormatOption },
+		options: {
+			weekdayFormat: weekdayFormatOption,
+			numberOfMonths: numberOfMonthsOption,
+			fixedWeeks: fixedWeeksOption,
+			weekStartsOn: weekStartsOnOption,
+			locale: localeOption,
+		},
 	} = createCalendar(
 		removeUndefined({
 			value,
@@ -58,6 +64,10 @@
 		})
 	);
 
+	function cycleWeekStart() {
+		$weekStartsOnOption = (($weekStartsOnOption + 1) % 7) as typeof $weekStartsOnOption;
+	}
+
 	function cycleWeekdayFormat() {
 		weekdayFormatOption.update((prev) => {
 			switch (prev) {
@@ -95,7 +105,7 @@
 					{#each $months as month, i}
 						<table use:melt={$grid} class="w-full" data-testid="grid-{i}">
 							<thead aria-hidden="true">
-								<tr>
+								<tr data-testid="weekdays">
 									{#each $weekdays as day, idx}
 										<th class="text-sm font-semibold text-magnum-800">
 											<div
@@ -134,6 +144,28 @@
 	<button on:click={cycleWeekdayFormat} data-testid="cycle-weekday-format">
 		Cycle weekdayFormat
 	</button>
+	<button
+		data-testid="numberOfMonths"
+		on:click={() => {
+			$numberOfMonthsOption++;
+		}}>numberOfMonths</button
+	>
+	<br />
+	<button data-testid="weekStartsOn" on:click={cycleWeekStart}>weekStartsOn</button>
+	<br />
+	<button
+		data-testid="fixedWeeks"
+		on:click={() => {
+			$fixedWeeksOption = !$fixedWeeksOption;
+		}}>fixedWeeksOption</button
+	>
+	<br />
+	<button
+		data-testid="locale"
+		on:click={() => {
+			$localeOption = 'it';
+		}}>setLocaleToIt</button
+	>
 </main>
 
 <style lang="postcss">
diff --git a/src/tests/combobox/Combobox.spec.ts b/src/tests/combobox/Combobox.spec.ts
index a8165609..57532d02 100644
--- a/src/tests/combobox/Combobox.spec.ts
+++ b/src/tests/combobox/Combobox.spec.ts
@@ -315,6 +315,11 @@ describe('Combobox (forceVisible)', () => {
 		const { getByTestId, queryByTestId } = render(ComboboxForceVisibleTest, { options });
 		const input = getByTestId('input');
 		const getMenu = () => queryByTestId('menu');
+		const getFirstItem = () => {
+			const firstItem = getMenu()?.querySelector('[data-melt-combobox-option]');
+			if (!firstItem) throw new Error('No option found');
+			return firstItem;
+		};
 
 		expect(input).not.toHaveValue(options[0].label);
 
@@ -323,10 +328,7 @@ describe('Combobox (forceVisible)', () => {
 		expect(getMenu()).not.toBeNull();
 		expect(getMenu()).toBeVisible();
 
-		const firstItem = getMenu()?.querySelector('[data-melt-combobox-option]');
-		if (!firstItem) throw new Error('No option found');
-
-		await user.click(firstItem);
+		await user.click(getFirstItem());
 
 		expect(getMenu()).toBeNull();
 		expect(input).toHaveValue(options[0].label);
@@ -334,7 +336,7 @@ describe('Combobox (forceVisible)', () => {
 		await user.click(input);
 		expect(getMenu()).not.toBeNull();
 		expect(getMenu()).toBeVisible();
-		expect(firstItem).toHaveAttribute('data-selected');
+		expect(getFirstItem()).toHaveAttribute('data-selected');
 	});
 
 	test('Applies custom ids when provided', async () => {
diff --git a/src/tests/date-field/DateField.spec.ts b/src/tests/date-field/DateField.spec.ts
index 1e89ce5e..34e5b186 100644
--- a/src/tests/date-field/DateField.spec.ts
+++ b/src/tests/date-field/DateField.spec.ts
@@ -1,5 +1,5 @@
 import { testKbd as kbd } from '../utils.js';
-import { render } from '@testing-library/svelte';
+import { render, waitFor } from '@testing-library/svelte';
 import { userEvent } from '@testing-library/user-event';
 import { axe } from 'jest-axe';
 import { describe } from 'vitest';
@@ -125,13 +125,14 @@ describe('DateField', () => {
 		});
 		expect(queryByTestId('dayPeriod')).not.toBeNull();
 	});
+
 	test('focuses first segment on click', async () => {
 		const { getByTestId, user } = setup();
 
 		const firstSegment = getByTestId('month');
 		await user.click(firstSegment);
 
-		expect(firstSegment).toHaveFocus();
+		await waitFor(() => expect(firstSegment).toHaveFocus());
 	});
 
 	test('increments segment on arrow up', async () => {
@@ -193,16 +194,16 @@ describe('DateField', () => {
 
 		await user.click(monthSegment);
 		await user.keyboard(kbd.ARROW_RIGHT);
-		expect(daySegment).toHaveFocus();
+		await waitFor(() => expect(daySegment).toHaveFocus());
 
 		await user.keyboard(kbd.ARROW_RIGHT);
-		expect(yearSegment).toHaveFocus();
+		await waitFor(() => expect(yearSegment).toHaveFocus());
 
 		await user.keyboard(kbd.ARROW_LEFT);
-		expect(daySegment).toHaveFocus();
+		await waitFor(() => expect(daySegment).toHaveFocus());
 
 		await user.keyboard(kbd.ARROW_LEFT);
-		expect(monthSegment).toHaveFocus();
+		await waitFor(() => expect(monthSegment).toHaveFocus());
 	});
 
 	test('navigates segments using tab', async () => {
@@ -214,10 +215,10 @@ describe('DateField', () => {
 
 		await user.click(monthSegment);
 		await user.keyboard(kbd.TAB);
-		expect(daySegment).toHaveFocus();
+		await waitFor(() => expect(daySegment).toHaveFocus());
 
 		await user.keyboard(kbd.TAB);
-		expect(yearSegment).toHaveFocus();
+		await waitFor(() => expect(yearSegment).toHaveFocus());
 	});
 
 	test('disabled prop prevents interaction', async () => {
@@ -229,16 +230,17 @@ describe('DateField', () => {
 		const yearSegment = getByTestId('year');
 
 		await user.click(monthSegment);
-		expect(monthSegment).not.toHaveFocus();
+		await waitFor(() => expect(monthSegment).not.toHaveFocus());
 		await user.keyboard(kbd.ARROW_RIGHT);
-		expect(daySegment).not.toHaveFocus();
+		await waitFor(() => expect(daySegment).not.toHaveFocus());
 		await user.keyboard(kbd.ARROW_RIGHT);
+		await waitFor(() => expect(yearSegment).not.toHaveFocus());
 		expect(yearSegment).not.toHaveFocus();
 
 		await user.click(daySegment);
-		expect(daySegment).not.toHaveFocus();
+		await waitFor(() => expect(daySegment).not.toHaveFocus());
 		await user.click(yearSegment);
-		expect(yearSegment).not.toHaveFocus();
+		await waitFor(() => expect(yearSegment).not.toHaveFocus());
 	});
 
 	test('readonly prop prevents modifying segments', async () => {
@@ -250,11 +252,12 @@ describe('DateField', () => {
 
 		for (const segment of segments) {
 			const el = getByTestId(segment);
+
 			expect(el).toHaveTextContent(String(calendarDateOther[segment]));
 			await user.click(el);
-			expect(el).toHaveFocus();
+			await waitFor(() => expect(el).toHaveFocus());
 			await user.keyboard(kbd.ARROW_UP);
-			expect(el).toHaveTextContent(String(calendarDateOther[segment]));
+			await waitFor(() => expect(el).toHaveTextContent(String(calendarDateOther[segment])));
 		}
 	});
 
@@ -268,17 +271,17 @@ describe('DateField', () => {
 		const monthSegment = getByTestId('month');
 		expect(monthSegment).toHaveTextContent(String(calendarDateOther['month']));
 		await user.click(monthSegment);
-		expect(monthSegment).toHaveFocus();
+		await waitFor(() => expect(monthSegment).toHaveFocus());
 		await user.keyboard(kbd.ARROW_UP);
-		expect(monthSegment).toHaveTextContent(String(calendarDateOther['month']));
+		await waitFor(() => expect(monthSegment).toHaveTextContent(String(calendarDateOther['month'])));
 
 		// day should change
 		const daySegment = getByTestId('day');
-		expect(daySegment).toHaveTextContent(String(calendarDateOther['day']));
+		await waitFor(() => expect(daySegment).toHaveTextContent(String(calendarDateOther['day'])));
 		await user.click(daySegment);
-		expect(daySegment).toHaveFocus();
+		await waitFor(() => expect(daySegment).toHaveFocus());
 		await user.keyboard(kbd.ARROW_UP);
-		expect(daySegment).toHaveTextContent(String(calendarDateOther['day'] + 1));
+		await waitFor(() => expect(daySegment).toHaveTextContent(String(calendarDateOther['day'] + 1)));
 	});
 
 	test('if selected date unavailable, mark field as invalid', async () => {
@@ -586,7 +589,7 @@ describe('DateField', () => {
 		expect(secondSegment).toHaveTextContent('00');
 	});
 
-	test('displays correct timezone with ZonedDateTime value - now', async () => {
+	test.skip('displays correct timezone with ZonedDateTime value - now', async () => {
 		const { getByTestId } = setup({
 			defaultValue: now('America/Los_Angeles'),
 		});
@@ -669,14 +672,11 @@ describe('DateField', () => {
 	});
 });
 
-function isDaylightSavingsTime(): boolean {
+function isDaylightSavingsTime() {
 	const now = new Date();
-	const january = new Date(now.getFullYear(), 0, 1);
-	const july = new Date(now.getFullYear(), 6, 1);
-	const timezoneOffset = now.getTimezoneOffset();
-	const isDaylightSavingsTime =
-		timezoneOffset < Math.max(january.getTimezoneOffset(), july.getTimezoneOffset());
-	return isDaylightSavingsTime;
+	const januaryOffset = new Date(now.getFullYear(), 0, 1).getTimezoneOffset();
+	const julyOffset = new Date(now.getFullYear(), 6, 1).getTimezoneOffset();
+	return januaryOffset !== julyOffset;
 }
 
 function thisTimeZone(date: string): string {
diff --git a/src/tests/date-picker/DatePicker.spec.ts b/src/tests/date-picker/DatePicker.spec.ts
index 2ff9089e..e7f973b4 100644
--- a/src/tests/date-picker/DatePicker.spec.ts
+++ b/src/tests/date-picker/DatePicker.spec.ts
@@ -560,4 +560,66 @@ describe('DatePicker', () => {
 
 		expect(trigger).toBeDisabled();
 	});
+
+	test('dynamically change numberOfMonths option even if numberOfMonths is specified as an option', async () => {
+		const { queryByTestId, getByTestId, user } = setup({
+			numberOfMonths: 1,
+		});
+
+		let grid0 = queryByTestId('grid-0');
+		let grid1 = queryByTestId('grid-1');
+		expect(grid0).toBeInTheDocument();
+		expect(grid1).toBeNull();
+
+		const numberOfMonthsButton = getByTestId('numberOfMonths');
+		await user.click(numberOfMonthsButton);
+
+		grid0 = queryByTestId('grid-0');
+		grid1 = queryByTestId('grid-1');
+		expect(grid0).toBeInTheDocument();
+		expect(grid1).toBeInTheDocument();
+	});
+
+	test('dynamically change weekStartsOn option even if weekStartsOn option is set', async () => {
+		const { getByTestId, user } = setup({
+			weekStartsOn: 0,
+		});
+
+		const weekDaysCopy = [...narrowWeekdays];
+
+		let weekdayElement = getByTestId(`weekdays`);
+
+		for (let i = 0; i < weekDaysCopy.length; i++) {
+			expect(weekdayElement.children[i]).toHaveTextContent(weekDaysCopy[i]);
+		}
+
+		const weekStartsOnButton = getByTestId('weekStartsOn');
+		await user.click(weekStartsOnButton);
+		const first = weekDaysCopy.shift();
+		if (first) {
+			weekDaysCopy.push(first);
+		}
+
+		weekdayElement = getByTestId(`weekdays`);
+		for (let i = 0; i < weekDaysCopy.length; i++) {
+			expect(weekdayElement.children[i]).toHaveTextContent(weekDaysCopy[i]);
+		}
+	});
+
+	test('dynamically change fixedWeeks option even if fixedWeeks option is set', async () => {
+		const { getByTestId, queryByTestId, user } = setup({
+			fixedWeeks: false,
+		});
+
+		const nextButton = getByTestId('next-button');
+
+		while (queryByTestId('week-6') !== null) {
+			await user.click(nextButton);
+		}
+
+		const fixedWeeksButton = getByTestId('fixedWeeks');
+		await user.click(fixedWeeksButton);
+
+		expect(queryByTestId('week-6')).not.toBeNull();
+	});
 });
diff --git a/src/tests/date-picker/DatePickerTest.svelte b/src/tests/date-picker/DatePickerTest.svelte
index 86596a9b..56a2ece7 100644
--- a/src/tests/date-picker/DatePickerTest.svelte
+++ b/src/tests/date-picker/DatePickerTest.svelte
@@ -27,6 +27,7 @@
 	export let placeholder: CreateDatePickerProps['placeholder'] = undefined;
 	export let weekStartsOn: CreateDatePickerProps['weekStartsOn'] = undefined;
 	export let weekdayFormat: CreateDatePickerProps['weekdayFormat'] = undefined;
+	export let fixedWeeks: CreateDatePickerProps['fixedWeeks'] = undefined;
 	export let onOutsideClick: CreateDatePickerProps['onOutsideClick'] = undefined;
 
 	const {
@@ -45,7 +46,13 @@
 			validation,
 		},
 		states: { value: insideValue, months, headingValue, weekdays, segmentContents },
-		options: { locale: insideLocale, weekdayFormat: weekdayFormatOption },
+		options: {
+			locale: insideLocale,
+			weekdayFormat: weekdayFormatOption,
+			numberOfMonths: numberOfMonthsOption,
+			fixedWeeks: fixedWeeksOption,
+			weekStartsOn: weekStartsOnOption,
+		},
 	} = createDatePicker(
 		removeUndefined({
 			value,
@@ -72,9 +79,14 @@
 			weekdayFormat,
 			popoverIds,
 			onOutsideClick,
+			fixedWeeks,
 		})
 	);
 
+	function cycleWeekStart() {
+		$weekStartsOnOption = (($weekStartsOnOption + 1) % 7) as typeof $weekStartsOnOption;
+	}
+
 	function cycleWeekdayFormat() {
 		weekdayFormatOption.update((prev) => {
 			switch (prev) {
@@ -138,7 +150,7 @@
 				{@const { weeks } = month}
 				<table use:melt={$grid} class="w-full" data-testid="grid-{i}">
 					<thead aria-hidden="true">
-						<tr>
+						<tr data-testid="weekdays">
 							{#each $weekdays as day, idx}
 								<th class="text-sm font-semibold text-magnum-800">
 									<div
@@ -152,8 +164,8 @@
 						</tr>
 					</thead>
 					<tbody>
-						{#each weeks as days}
-							<tr>
+						{#each weeks as days, i}
+							<tr data-testid="week-{i + 1}">
 								{#each days as date}
 									<td role="gridcell">
 										<div
@@ -174,6 +186,21 @@
 		<button on:click={cycleWeekdayFormat} data-testid="cycle-weekday-format">
 			Cycle weekdayFormat
 		</button>
+		<button
+			data-testid="numberOfMonths"
+			on:click={() => {
+				$numberOfMonthsOption++;
+			}}>numberOfMonths</button
+		>
+		<br />
+		<button data-testid="weekStartsOn" on:click={cycleWeekStart}>weekStartsOn</button>
+		<br />
+		<button
+			data-testid="fixedWeeks"
+			on:click={() => {
+				$fixedWeeksOption = !$fixedWeeksOption;
+			}}>fixedWeeksOption</button
+		>
 	</div>
 </main>
 
diff --git a/src/tests/dialog/Dialog.spec.ts b/src/tests/dialog/Dialog.spec.ts
index c9dedae1..384a138a 100644
--- a/src/tests/dialog/Dialog.spec.ts
+++ b/src/tests/dialog/Dialog.spec.ts
@@ -230,6 +230,30 @@ describe('Dialog', () => {
 		await waitFor(() => expect(content).not.toBeVisible());
 	});
 
+	it('Respects the `closeOnEscape` prop', async () => {
+		const { getByTestId, user, trigger } = setup({
+			closeOnEscape: false,
+		});
+		expect(trigger).toBeVisible();
+		const content = getByTestId('content');
+		expect(content).not.toBeVisible();
+		await user.click(trigger);
+		expect(content).toBeVisible();
+		await user.keyboard(kbd.ESCAPE);
+		expect(content).toBeVisible();
+	});
+
+	it("Doesn't close on escape if child intercepts event", async () => {
+		const { getByTestId, user, trigger } = setup();
+		await user.click(trigger);
+		const content = getByTestId('content');
+		expect(content).toBeVisible();
+		const input = getByTestId('input-keydown-interceptor');
+		input.focus();
+		await user.keyboard(kbd.ESCAPE);
+		expect(content).toBeVisible();
+	});
+
 	it('Applies custom ids when provided', async () => {
 		const ids = {
 			content: 'id-content',
@@ -277,4 +301,34 @@ describe('Dialog', () => {
 		await user.pointer({ target: overlay, offset: 2, keys: '[/MouseLeft]' });
 		expect(content).not.toBeVisible();
 	});
+
+	it("Doesn't deactivate focus trap on escape provided `closeOnEscape` false", async () => {
+		const { getByTestId, user, trigger } = setup({
+			closeOnEscape: false,
+		});
+		const content = getByTestId('content');
+		expect(content).not.toBeVisible();
+		await user.click(trigger);
+		expect(content).toBeVisible();
+		await user.keyboard(kbd.ESCAPE);
+		expect(content).toBeVisible();
+		expect(getByTestId('content')).toHaveFocus();
+		await user.tab({ shift: true });
+		expect(getByTestId('floating-closer')).not.toHaveFocus();
+	});
+
+	it("Doesn't deactivate focus trap on outside click provided `closeOnOutsideClick` false", async () => {
+		const { getByTestId, user, trigger } = setup({
+			closeOnOutsideClick: false,
+		});
+		const content = getByTestId('content');
+		expect(content).not.toBeVisible();
+		await user.click(trigger);
+		expect(content).toBeVisible();
+		await user.click(getByTestId('overlay'));
+		expect(content).toBeVisible();
+		expect(getByTestId('content')).toHaveFocus();
+		await user.tab({ shift: true });
+		expect(getByTestId('floating-closer')).not.toHaveFocus();
+	});
 });
diff --git a/src/tests/dialog/DialogNestedTest.svelte b/src/tests/dialog/DialogNestedTest.svelte
index 110398c8..ac5f2820 100644
--- a/src/tests/dialog/DialogNestedTest.svelte
+++ b/src/tests/dialog/DialogNestedTest.svelte
@@ -22,8 +22,8 @@
 
 <main>
 	<button use:melt={$trigger} data-testid="trigger">Open</button>
-	<div use:melt={$portalled} data-testid="portalled">
-		{#if $open}
+	{#if $open}
+		<div use:melt={$portalled} data-testid="portalled">
 			<div use:melt={$overlay} data-testid="overlay" transition:fade />
 			<div use:melt={$content} data-testid="content">
 				<h2 use:melt={$title}>Title</h2>
@@ -31,8 +31,8 @@
 
 				<button use:melt={$close} data-testid="closer">Close</button>
 				<button use:melt={$triggerA} data-testid="triggerA">Close2</button>
-				<div use:melt={$portalledA} data-testid="portalledA">
-					{#if $openA}
+				{#if $openA}
+					<div use:melt={$portalledA} data-testid="portalledA">
 						<div use:melt={$overlayA} data-testid="overlayA" />
 						<div use:melt={$contentA} data-testid="contentA" transition:fade>
 							<h2 use:melt={$titleA}>Title</h2>
@@ -41,11 +41,11 @@
 							<button use:melt={$closeA} data-testid="closerA">Close</button>
 							<button use:melt={$closeA} data-testid="lastA">Close2</button>
 						</div>
-					{/if}
-				</div>
+					</div>
+				{/if}
 			</div>
-		{/if}
-	</div>
+		</div>
+	{/if}
 </main>
 
 <style>
diff --git a/src/tests/dialog/DialogTest.svelte b/src/tests/dialog/DialogTest.svelte
index 0c0b213a..60d8e2ea 100644
--- a/src/tests/dialog/DialogTest.svelte
+++ b/src/tests/dialog/DialogTest.svelte
@@ -1,5 +1,6 @@
 <script lang="ts">
 	import { createDialog, melt, type CreateDialogProps } from '$lib/index.js';
+	import { kbd } from '$lib/internal/helpers/keyboard.js';
 
 	type $$Props = CreateDialogProps;
 
@@ -19,6 +20,11 @@
 		<div use:melt={$content} data-testid="content">
 			<h2 use:melt={$title} data-testid="title">Title</h2>
 			<p use:melt={$description} data-testid="description">Description</p>
+			<input
+				data-testid="input-keydown-interceptor"
+				type="text"
+				on:keydown={(e) => e.key === kbd.ESCAPE && e.stopPropagation()}
+			/>
 
 			<button use:melt={$close} data-testid="closer">Close</button>
 			<button use:melt={$close} data-testid="last">Close</button>
diff --git a/src/tests/popover/Popover.spec.ts b/src/tests/popover/Popover.spec.ts
index 676c4f24..7d1f5664 100644
--- a/src/tests/popover/Popover.spec.ts
+++ b/src/tests/popover/Popover.spec.ts
@@ -135,4 +135,33 @@ describe('Popover (Default)', () => {
 		expect(trigger.id).toBe(ids.trigger);
 		expect(content.id).toBe(ids.content);
 	});
+
+	it("Doesn't deactivate focus trap on escape provided `closeOnEscape` false", async () => {
+		const { getByTestId, user, trigger } = setup({
+			closeOnEscape: false,
+		});
+		const content = getByTestId('content');
+		expect(content).not.toBeVisible();
+		await user.click(trigger);
+		expect(content).toBeVisible();
+		await user.keyboard(kbd.ESCAPE);
+		expect(content).toBeVisible();
+		expect(getByTestId('content')).toHaveFocus();
+		await user.tab({ shift: true });
+		expect(getByTestId('trigger')).not.toHaveFocus();
+	});
+
+	it("Doesn't deactivate focus trap on outside click provided `closeOnOutsideClick` false", async () => {
+		const { getByTestId, user, trigger } = setup({
+			closeOnOutsideClick: false,
+		});
+		const content = getByTestId('content');
+		expect(content).not.toBeVisible();
+		await user.click(trigger);
+		expect(content).toBeVisible();
+		await user.click(getByTestId('outside'));
+		expect(content).toBeVisible();
+		await user.tab();
+		expect(getByTestId('closeFocus')).not.toHaveFocus();
+	});
 });
diff --git a/src/tests/portal/PopoverTooltip.svelte b/src/tests/portal/PopoverTooltip.svelte
new file mode 100644
index 00000000..c73ea7f3
--- /dev/null
+++ b/src/tests/portal/PopoverTooltip.svelte
@@ -0,0 +1,35 @@
+<script lang="ts">
+	import { createPopover, createTooltip, melt } from '$lib/index.js';
+	import { Settings2 } from '$icons/index.js';
+
+	const {
+		elements: { trigger, content, arrow, close },
+	} = createPopover();
+
+	const {
+		elements: { trigger: ttTrigger, content: ttContent },
+	} = createTooltip({
+		openDelay: 0,
+		closeDelay: 0,
+	});
+</script>
+
+<button
+	type="button"
+	class="trigger"
+	use:melt={$trigger}
+	aria-label="Update dimensions"
+	data-testid="popover-trigger"
+>
+	<Settings2 class="h-4 w-4" />
+	<span class="sr-only">Open Popover</span>
+</button>
+
+<div use:melt={$content} data-testid="popover-content">
+	<div use:melt={$arrow} data-testid="popover-arrow" />
+	<button use:melt={$ttTrigger} data-testid="tooltip-trigger"> Open tooltip </button>
+	<div use:melt={$ttContent} data-testid="tooltip-content">Tooltip content</div>
+	<button use:melt={$close} data-testid="popover-close"> Close </button>
+</div>
+<div class="mt-48 h-[500px] w-[500px] bg-black" />
+<div data-testid="outside" class="h-5 w-5" />
diff --git a/src/tests/portal/Portal.spec.ts b/src/tests/portal/Portal.spec.ts
new file mode 100644
index 00000000..89a3c56e
--- /dev/null
+++ b/src/tests/portal/Portal.spec.ts
@@ -0,0 +1,69 @@
+import { describe, it } from 'vitest';
+import { render, waitFor } from '@testing-library/svelte';
+import { userEvent } from '@testing-library/user-event';
+import PopoverTooltip from './PopoverTooltip.svelte';
+import { sleep } from '$lib/internal/helpers/sleep.js';
+
+function setupPopoverTooltip() {
+	const user = userEvent.setup();
+	const returned = render(PopoverTooltip);
+	const popoverTrigger = returned.getByTestId('popover-trigger');
+	const popoverContent = returned.getByTestId('popover-content');
+	const tooltipTrigger = returned.getByTestId('tooltip-trigger');
+	const tooltipContent = returned.getByTestId('tooltip-content');
+	const outside = returned.getByTestId('outside');
+	const elements = { popoverTrigger, popoverContent, tooltipTrigger, tooltipContent, outside };
+	return { user, ...returned, elements };
+}
+
+describe('Portal Behaviors - Popover & Tooltip', () => {
+	it('should not close the popover when the tooltip content is clicked', async () => {
+		const { elements, user } = setupPopoverTooltip();
+
+		expect(elements.popoverContent).not.toBeVisible();
+		await user.click(elements.popoverTrigger);
+		expect(elements.popoverContent).toBeVisible();
+		expect(elements.tooltipContent).not.toBeVisible();
+		await user.hover(elements.tooltipTrigger);
+		expect(elements.tooltipContent).toBeVisible();
+		await user.click(elements.tooltipContent);
+		expect(elements.tooltipContent).toBeVisible();
+		expect(elements.popoverContent).toBeVisible();
+	});
+
+	it('should close the tooltip content when the popover content is clicked and tooltip is open', async () => {
+		const { elements, user } = setupPopoverTooltip();
+
+		expect(elements.popoverContent).not.toBeVisible();
+		await user.click(elements.popoverTrigger);
+		expect(elements.popoverContent).toBeVisible();
+		expect(elements.tooltipContent).not.toBeVisible();
+		await user.hover(elements.tooltipTrigger);
+		expect(elements.tooltipContent).toBeVisible();
+		await user.click(elements.tooltipContent);
+		expect(elements.tooltipContent).toBeVisible();
+		expect(elements.popoverContent).toBeVisible();
+		await user.click(elements.popoverContent);
+		expect(elements.tooltipContent).not.toBeVisible();
+		expect(elements.popoverContent).toBeVisible();
+	});
+
+	it('should close both tooltip and popover content when clicked outside of popover content', async () => {
+		const { elements, user } = setupPopoverTooltip();
+
+		expect(elements.popoverContent).not.toBeVisible();
+		await user.click(elements.popoverTrigger);
+		expect(elements.popoverContent).toBeVisible();
+		expect(elements.tooltipContent).not.toBeVisible();
+		await user.hover(elements.tooltipTrigger);
+		expect(elements.tooltipContent).toBeVisible();
+		await user.click(elements.tooltipContent);
+		expect(elements.tooltipContent).toBeVisible();
+		expect(elements.popoverContent).toBeVisible();
+		await sleep(100);
+		expect(elements.outside).toBeVisible();
+		await user.click(elements.outside);
+		await waitFor(() => expect(elements.tooltipContent).not.toBeVisible());
+		await waitFor(() => expect(elements.popoverContent).not.toBeVisible());
+	});
+});
diff --git a/src/tests/range-calendar/RangeCalendar.spec.ts b/src/tests/range-calendar/RangeCalendar.spec.ts
index 5f9744a6..3bb62e3e 100644
--- a/src/tests/range-calendar/RangeCalendar.spec.ts
+++ b/src/tests/range-calendar/RangeCalendar.spec.ts
@@ -501,6 +501,75 @@ describe('Range Calendar', () => {
 		}
 	});
 
+	test('dynamically change numberOfMonths option', async () => {
+		const { queryByTestId, getByTestId, user } = setup();
+
+		let grid0 = queryByTestId('grid-0');
+		let grid1 = queryByTestId('grid-1');
+		expect(grid0).toBeInTheDocument();
+		expect(grid1).toBeNull();
+
+		const numberOfMonthsButton = getByTestId('numberOfMonths');
+		await user.click(numberOfMonthsButton);
+
+		grid0 = queryByTestId('grid-0');
+		grid1 = queryByTestId('grid-1');
+		expect(grid0).toBeInTheDocument();
+		expect(grid1).toBeInTheDocument();
+	});
+
+	test('dynamically change weekStartsOn option', async () => {
+		const { getByTestId, user } = setup();
+
+		const weekDaysCopy = [...narrowWeekdays];
+
+		let weekdayElement = getByTestId(`weekdays`);
+
+		for (let i = 0; i < weekDaysCopy.length; i++) {
+			expect(weekdayElement.children[i]).toHaveTextContent(weekDaysCopy[i]);
+		}
+
+		const weekStartsOnButton = getByTestId('weekStartsOn');
+		await user.click(weekStartsOnButton);
+		const first = weekDaysCopy.shift();
+		if (first) {
+			weekDaysCopy.push(first);
+		}
+
+		weekdayElement = getByTestId(`weekdays`);
+		for (let i = 0; i < weekDaysCopy.length; i++) {
+			expect(weekdayElement.children[i]).toHaveTextContent(weekDaysCopy[i]);
+		}
+	});
+
+	test('dynamically change fixedWeeks option', async () => {
+		const { getByTestId, queryByTestId, user } = setup();
+
+		const nextButton = getByTestId('next-button');
+
+		while (queryByTestId('week-6') !== null) {
+			await user.click(nextButton);
+		}
+
+		const fixedWeeksButton = getByTestId('fixedWeeks');
+		await user.click(fixedWeeksButton);
+
+		expect(queryByTestId('week-6')).not.toBeNull();
+	});
+
+	test('dynamically changing the locale option also update weekStartsOn', async () => {
+		const { getByTestId, user } = setup();
+
+		let weekdayElement = getByTestId(`weekday-0`);
+		expect(weekdayElement).toHaveTextContent('S');
+
+		const localeButton = getByTestId('locale');
+		await user.click(localeButton);
+		weekdayElement = getByTestId(`weekday-0`);
+		// L is italian for Lunedì which is Monday (which is different from S which is Sunday)
+		expect(weekdayElement).toHaveTextContent('L');
+	});
+
 	test('custom ids are applied when provided', async () => {
 		const ids = {
 			accessibleHeading: 'id-heading',
diff --git a/src/tests/range-calendar/RangeCalendarTest.svelte b/src/tests/range-calendar/RangeCalendarTest.svelte
index f9160fe1..4961f63b 100644
--- a/src/tests/range-calendar/RangeCalendarTest.svelte
+++ b/src/tests/range-calendar/RangeCalendarTest.svelte
@@ -27,7 +27,13 @@
 	const {
 		elements: { calendar, heading, grid, cell, prevButton, nextButton },
 		states: { value: insideValue, months, headingValue, weekdays },
-		options: { weekdayFormat: weekdayFormatOption },
+		options: {
+			weekdayFormat: weekdayFormatOption,
+			numberOfMonths: numberOfMonthsOption,
+			fixedWeeks: fixedWeeksOption,
+			locale: localeOption,
+			weekStartsOn: weekStartsOnOption,
+		},
 	} = createRangeCalendar(
 		removeUndefined({
 			value,
@@ -64,6 +70,10 @@
 			}
 		});
 	}
+
+	function cycleWeekStart() {
+		$weekStartsOnOption = (($weekStartsOnOption + 1) % 7) as typeof $weekStartsOnOption;
+	}
 </script>
 
 <main class="flex h-full">
@@ -91,7 +101,7 @@
 					{@const { weeks } = month}
 					<table use:melt={$grid} class="w-full" data-testid="grid-{i}">
 						<thead aria-hidden="true">
-							<tr>
+							<tr data-testid="weekdays">
 								{#each $weekdays as day, idx}
 									<th class="text-sm font-semibold text-magnum-800">
 										<div
@@ -129,6 +139,28 @@
 	<button on:click={cycleWeekdayFormat} data-testid="cycle-weekday-format">
 		Cycle weekdayFormat
 	</button>
+	<button
+		data-testid="numberOfMonths"
+		on:click={() => {
+			$numberOfMonthsOption++;
+		}}>numberOfMonths</button
+	>
+	<br />
+	<button data-testid="weekStartsOn" on:click={cycleWeekStart}>weekStartsOn</button>
+	<br />
+	<button
+		data-testid="fixedWeeks"
+		on:click={() => {
+			$fixedWeeksOption = !$fixedWeeksOption;
+		}}>fixedWeeksOption</button
+	>
+	<br />
+	<button
+		data-testid="locale"
+		on:click={() => {
+			$localeOption = 'it';
+		}}>setLocaleToIt</button
+	>
 </main>
 
 <style lang="postcss">
diff --git a/src/tests/slider/Slider.spec.ts b/src/tests/slider/Slider.spec.ts
index df42592f..d6f99ba7 100644
--- a/src/tests/slider/Slider.spec.ts
+++ b/src/tests/slider/Slider.spec.ts
@@ -1,4 +1,4 @@
-import { kbd } from '$lib/internal/helpers/index.js';
+import { testKbd as kbd } from '../utils.js';
 import { act, render } from '@testing-library/svelte';
 import { userEvent } from '@testing-library/user-event';
 import { axe } from 'jest-axe';
@@ -89,7 +89,7 @@ describe('Slider (Default)', () => {
 		const range = getByTestId('range');
 
 		await act(() => thumb.focus());
-		await user.keyboard(`{${key}}`);
+		await user.keyboard(key);
 
 		expectPercentage({ percentage: 31, thumb, range });
 	});
@@ -102,7 +102,7 @@ describe('Slider (Default)', () => {
 		const range = getByTestId('range');
 
 		await act(() => thumb.focus());
-		await user.keyboard(`{${key}}`);
+		await user.keyboard(key);
 
 		expectPercentage({ percentage: 29, thumb, range });
 	});
@@ -115,7 +115,7 @@ describe('Slider (Default)', () => {
 		const range = getByTestId('range');
 
 		await act(() => thumb.focus());
-		await user.keyboard(`{${kbd.HOME}}`);
+		await user.keyboard(kbd.HOME);
 
 		expectPercentage({ percentage: 0, thumb, range });
 	});
@@ -127,7 +127,7 @@ describe('Slider (Default)', () => {
 		const range = getByTestId('range');
 
 		await act(() => thumb.focus());
-		await user.keyboard(`{${kbd.END}}`);
+		await user.keyboard(kbd.END);
 
 		expectPercentage({ percentage: 100, thumb, range });
 	});
@@ -172,7 +172,7 @@ describe('Slider (Range)', () => {
 			const range = getByTestId('range');
 
 			await act(() => thumb0.focus());
-			await user.keyboard(`{${key}}`);
+			await user.keyboard(key);
 
 			expectPercentages({ percentages: [21, 80], thumbs: [thumb0, thumb1], range });
 		}
@@ -189,7 +189,7 @@ describe('Slider (Range)', () => {
 			const range = getByTestId('range');
 
 			await act(() => thumb1.focus());
-			await user.keyboard(`{${key}}`);
+			await user.keyboard(key);
 
 			expectPercentages({ percentages: [20, 81], thumbs: [thumb0, thumb1], range });
 		}
@@ -206,7 +206,7 @@ describe('Slider (Range)', () => {
 			const range = getByTestId('range');
 
 			await act(() => thumb0.focus());
-			await user.keyboard(`{${key}}`);
+			await user.keyboard(key);
 
 			expectPercentages({ percentages: [19, 80], thumbs: [thumb0, thumb1], range });
 		}
@@ -223,7 +223,7 @@ describe('Slider (Range)', () => {
 			const range = getByTestId('range');
 
 			await act(() => thumb1.focus());
-			await user.keyboard(`{${key}}`);
+			await user.keyboard(key);
 
 			expectPercentages({ percentages: [20, 79], thumbs: [thumb0, thumb1], range });
 		}
@@ -242,9 +242,9 @@ describe('Slider (Range)', () => {
 			const range = getByTestId('range');
 
 			await act(() => thumb0.focus());
-			await user.keyboard(`{${key}}`);
-			await user.keyboard(`{${key}}`);
-			await user.keyboard(`{${key}}`);
+			await user.keyboard(key);
+			await user.keyboard(key);
+			await user.keyboard(key);
 
 			expectPercentages({ percentages: [51, 52], thumbs: [thumb0, thumb1], range });
 			expect(thumb1).toHaveFocus();
@@ -264,9 +264,9 @@ describe('Slider (Range)', () => {
 			const range = getByTestId('range');
 
 			await act(() => thumb1.focus());
-			await user.keyboard(`{${key}}`);
-			await user.keyboard(`{${key}}`);
-			await user.keyboard(`{${key}}`);
+			await user.keyboard(key);
+			await user.keyboard(key);
+			await user.keyboard(key);
 
 			expectPercentages({ percentages: [48, 49], thumbs: [thumb0, thumb1], range });
 			expect(thumb0).toHaveFocus();
@@ -282,7 +282,7 @@ describe('Slider (Range)', () => {
 		const range = getByTestId('range');
 
 		await act(() => thumb0.focus());
-		await user.keyboard(`{${kbd.HOME}}`);
+		await user.keyboard(kbd.HOME);
 
 		expectPercentages({ percentages: [0, 80], thumbs: [thumb0, thumb1], range });
 	});
@@ -296,7 +296,7 @@ describe('Slider (Range)', () => {
 		const range = getByTestId('range');
 
 		await act(() => thumb1.focus());
-		await user.keyboard(`{${kbd.END}}`);
+		await user.keyboard(kbd.END);
 
 		expectPercentages({ percentages: [20, 100], thumbs: [thumb0, thumb1], range });
 	});
@@ -310,7 +310,7 @@ describe('Slider (Range)', () => {
 		const range = getByTestId('range');
 
 		await act(() => thumb1.focus());
-		await user.keyboard(`{${kbd.HOME}}`);
+		await user.keyboard(kbd.HOME);
 
 		expectPercentages({ percentages: [0, 20], thumbs: [thumb0, thumb1], range });
 		expect(thumb0).toHaveFocus();
@@ -325,7 +325,7 @@ describe('Slider (Range)', () => {
 		const range = getByTestId('range');
 
 		await act(() => thumb0.focus());
-		await user.keyboard(`{${kbd.END}}`);
+		await user.keyboard(kbd.END);
 
 		expectPercentages({ percentages: [80, 100], thumbs: [thumb0, thumb1], range });
 		expect(thumb1).toHaveFocus();
@@ -361,7 +361,7 @@ describe('Slider (Small min, max, step)', () => {
 		const range = getByTestId('range');
 
 		await act(() => thumb.focus());
-		await user.keyboard(`{${key}}`);
+		await user.keyboard(key);
 
 		expectPercentage({ percentage: 51, thumb, range });
 	});
@@ -379,7 +379,7 @@ describe('Slider (Small min, max, step)', () => {
 		const range = getByTestId('range');
 
 		await act(() => thumb.focus());
-		await user.keyboard(`{${key}}`);
+		await user.keyboard(key);
 
 		expectPercentage({ percentage: 49, thumb, range });
 	});
@@ -414,7 +414,7 @@ describe('Slider (negative min)', () => {
 		const range = getByTestId('range');
 
 		await act(() => thumb.focus());
-		await user.keyboard(`{${key}}`);
+		await user.keyboard(key);
 
 		expectPercentage({ percentage: 51, thumb, range });
 	});
@@ -432,7 +432,7 @@ describe('Slider (negative min)', () => {
 		const range = getByTestId('range');
 
 		await act(() => thumb.focus());
-		await user.keyboard(`{${key}}`);
+		await user.keyboard(key);
 
 		expectPercentage({ percentage: 49, thumb, range });
 	});
@@ -581,10 +581,10 @@ describe('Slider (min=0, max=100, step=30)', () => {
 		expect(thumb).toBeInTheDocument();
 
 		await act(() => thumb.focus());
-		await user.keyboard(`{${kbd.ARROW_RIGHT}}`);
-		await user.keyboard(`{${kbd.ARROW_RIGHT}}`);
-		await user.keyboard(`{${kbd.ARROW_RIGHT}}`);
-		await user.keyboard(`{${kbd.ARROW_RIGHT}}`);
+		await user.keyboard(kbd.ARROW_RIGHT);
+		await user.keyboard(kbd.ARROW_RIGHT);
+		await user.keyboard(kbd.ARROW_RIGHT);
+		await user.keyboard(kbd.ARROW_RIGHT);
 
 		expectPercentage({ percentage: 90, thumb, range: getByTestId('range') });
 	});
diff --git a/src/tests/switch/Switch.spec.ts b/src/tests/switch/Switch.spec.ts
index 72fa80d3..f2a31754 100644
--- a/src/tests/switch/Switch.spec.ts
+++ b/src/tests/switch/Switch.spec.ts
@@ -3,7 +3,7 @@ import { axe } from 'jest-axe';
 import { describe, it } from 'vitest';
 import SwitchTest from './SwitchTest.svelte';
 import { userEvent } from '@testing-library/user-event';
-import { kbd } from '$lib/internal/helpers/index.js';
+import { testKbd as kbd } from '../utils.js';
 import { writable } from 'svelte/store';
 import { tick } from 'svelte';
 
@@ -35,11 +35,11 @@ describe('Switch', () => {
 		expect(switchEl).toHaveFocus();
 
 		for (const key of keys) {
-			await userEvent.keyboard(`{${key}}`);
+			await userEvent.keyboard(key);
 			expect(switchEl).toHaveAttribute('data-state', 'checked');
 			expect(switchEl).toHaveAttribute('aria-checked', 'true');
 
-			await userEvent.keyboard(`{${key}}`);
+			await userEvent.keyboard(key);
 			expect(switchEl).toHaveAttribute('data-state', 'unchecked');
 			expect(switchEl).toHaveAttribute('aria-checked', 'false');
 		}
diff --git a/src/tests/tabs/Tabs.spec.ts b/src/tests/tabs/Tabs.spec.ts
index 488ec116..8da38cad 100644
--- a/src/tests/tabs/Tabs.spec.ts
+++ b/src/tests/tabs/Tabs.spec.ts
@@ -1,4 +1,4 @@
-import { kbd } from '$lib/internal/helpers/keyboard.js';
+import { testKbd as kbd } from '../utils.js';
 import { render } from '@testing-library/svelte';
 import { userEvent } from '@testing-library/user-event';
 import { axe } from 'jest-axe';
@@ -34,7 +34,7 @@ describe('Tabs', () => {
 
 		for (const tab of tabs) {
 			expect(getByTestId(`${tab}-trigger`)).toHaveFocus();
-			await userEvent.keyboard(`{${kbd.ARROW_RIGHT}}`);
+			await userEvent.keyboard(kbd.ARROW_RIGHT);
 		}
 
 		const lastTrigger = getByTestId(`${tabs[tabs.length - 1]}-trigger`);
@@ -42,7 +42,7 @@ describe('Tabs', () => {
 
 		for (const tab of [...tabs].reverse()) {
 			expect(getByTestId(`${tab}-trigger`)).toHaveFocus();
-			await userEvent.keyboard(`{${kbd.ARROW_LEFT}}`);
+			await userEvent.keyboard(kbd.ARROW_LEFT);
 		}
 	});
 });
diff --git a/src/tests/tags-input/TagsInput.spec.ts b/src/tests/tags-input/TagsInput.spec.ts
index dd58ce49..2ffd97f3 100644
--- a/src/tests/tags-input/TagsInput.spec.ts
+++ b/src/tests/tags-input/TagsInput.spec.ts
@@ -1,4 +1,4 @@
-import { kbd } from '$lib/internal/helpers/index.js';
+import { testKbd as kbd } from '../utils.js';
 import { queryByText, render } from '@testing-library/svelte';
 import { userEvent } from '@testing-library/user-event';
 import { axe } from 'jest-axe';
@@ -33,7 +33,7 @@ describe('TagsInput', () => {
 		const input = await findByRole('textbox');
 		const user = userEvent.setup();
 		const newTag = 'new tag';
-		await user.type(input, `${newTag}{${kbd.ENTER}}`);
+		await user.type(input, `${newTag}${kbd.ENTER}`);
 		expect(input).not.toHaveValue();
 		expect(queryByText(newTag)).toBeInTheDocument();
 	});
@@ -49,7 +49,7 @@ describe('TagsInput', () => {
 
 		const input = await findByRole('textbox');
 		const user = userEvent.setup();
-		await user.type(input, `${newTag}{${kbd.ENTER}}`);
+		await user.type(input, `${newTag}${kbd.ENTER}`);
 		expect(input).toHaveValue();
 	});
 
@@ -68,7 +68,7 @@ describe('TagsInput', () => {
 
 		const input = await findByRole('textbox');
 		const user = userEvent.setup();
-		await user.type(input, `${newTag}   {${kbd.ENTER}}`);
+		await user.type(input, `${newTag}   ${kbd.ENTER}`);
 		expect(input).toHaveValue();
 	});
 
@@ -82,7 +82,7 @@ describe('TagsInput', () => {
 
 		const input = await findByRole('textbox');
 		const user = userEvent.setup();
-		await user.type(input, `${newTag}   {${kbd.ENTER}}`);
+		await user.type(input, `${newTag}   ${kbd.ENTER}`);
 		expect(input).not.toHaveValue();
 		expect(queryByText(newTag)).toBeInTheDocument();
 	});
@@ -99,7 +99,7 @@ describe('TagsInput', () => {
 
 		const input = await findByRole('textbox');
 		const user = userEvent.setup();
-		await user.type(input, `${newTag}   {${kbd.ENTER}}`);
+		await user.type(input, `${newTag}   ${kbd.ENTER}`);
 		expect(input).toHaveValue();
 	});
 
@@ -115,10 +115,10 @@ describe('TagsInput', () => {
 
 		const input = await findByRole('textbox');
 		const user = userEvent.setup();
-		await user.type(input, `${newTag}{${kbd.ENTER}}`);
+		await user.type(input, `${newTag}${kbd.ENTER}`);
 		expect(input).toHaveValue();
 		user.clear(input);
-		await user.type(input, `${allowedTag}{${kbd.ENTER}}`);
+		await user.type(input, `${allowedTag}${kbd.ENTER}`);
 		expect(input).not.toHaveValue();
 		expect(queryByText(allowedTag)).toBeInTheDocument();
 	});
@@ -135,10 +135,10 @@ describe('TagsInput', () => {
 
 		const input = await findByRole('textbox');
 		const user = userEvent.setup();
-		await user.type(input, `${newTag}   {${kbd.ENTER}}`);
+		await user.type(input, `${newTag}   ${kbd.ENTER}`);
 		expect(input).toHaveValue();
 		user.clear(input);
-		await user.type(input, `${allowedTag}    {${kbd.ENTER}}`);
+		await user.type(input, `${allowedTag}    ${kbd.ENTER}`);
 		expect(input).not.toHaveValue();
 		expect(queryByText(allowedTag)).toBeInTheDocument();
 	});
@@ -157,10 +157,10 @@ describe('TagsInput', () => {
 
 		const input = await findByRole('textbox');
 		const user = userEvent.setup();
-		await user.type(input, `${newTag}   {${kbd.ENTER}}`);
+		await user.type(input, `${newTag}   ${kbd.ENTER}`);
 		expect(input).toHaveValue();
 		user.clear(input);
-		await user.type(input, `${allowedTag}    {${kbd.ENTER}}`);
+		await user.type(input, `${allowedTag}    ${kbd.ENTER}`);
 		expect(input).not.toHaveValue();
 		expect(queryByText(allowedTag)).toBeInTheDocument();
 	});
diff --git a/src/tests/toolbar/Toolbar.spec.ts b/src/tests/toolbar/Toolbar.spec.ts
index 1f93f658..cd013dc1 100644
--- a/src/tests/toolbar/Toolbar.spec.ts
+++ b/src/tests/toolbar/Toolbar.spec.ts
@@ -1,4 +1,4 @@
-import { kbd } from '$lib/internal/helpers/keyboard.js';
+import { testKbd as kbd } from '../utils.js';
 import { render } from '@testing-library/svelte';
 import { userEvent } from '@testing-library/user-event';
 import { axe } from 'jest-axe';
@@ -113,8 +113,8 @@ describe('Toolbar', () => {
 		const user = userEvent.setup();
 		const { getByTestId } = render(ToolbarTest, props);
 
-		const nextKey = `{${props.orientation === horizontal ? kbd.ARROW_RIGHT : kbd.ARROW_DOWN}}`;
-		const prevKey = `{${props.orientation === horizontal ? kbd.ARROW_LEFT : kbd.ARROW_UP}}`;
+		const nextKey = props.orientation === horizontal ? kbd.ARROW_RIGHT : kbd.ARROW_DOWN;
+		const prevKey = props.orientation === horizontal ? kbd.ARROW_LEFT : kbd.ARROW_UP;
 
 		const reversedItems = [...items].reverse();
 
@@ -180,8 +180,8 @@ describe('Toolbar', () => {
 			const user = userEvent.setup();
 			const { getByTestId } = render(ToolbarTest, { loop: true, ...props });
 
-			const nextKey = `{${props.orientation === horizontal ? kbd.ARROW_RIGHT : kbd.ARROW_DOWN}}`;
-			const prevKey = `{${props.orientation === horizontal ? kbd.ARROW_LEFT : kbd.ARROW_UP}}`;
+			const nextKey = props.orientation === horizontal ? kbd.ARROW_RIGHT : kbd.ARROW_DOWN;
+			const prevKey = props.orientation === horizontal ? kbd.ARROW_LEFT : kbd.ARROW_UP;
 
 			await user.tab();
 			const firstItem = getByTestId(items[0]);
@@ -243,8 +243,8 @@ describe('Toolbar', () => {
 			const user = userEvent.setup();
 			const { getByTestId } = render(ToolbarTest, { loop: false, ...props });
 
-			const nextKey = `{${props.orientation === horizontal ? kbd.ARROW_RIGHT : kbd.ARROW_DOWN}}`;
-			const prevKey = `{${props.orientation === horizontal ? kbd.ARROW_LEFT : kbd.ARROW_UP}}`;
+			const nextKey = props.orientation === horizontal ? kbd.ARROW_RIGHT : kbd.ARROW_DOWN;
+			const prevKey = props.orientation === horizontal ? kbd.ARROW_LEFT : kbd.ARROW_UP;
 
 			const firstItem = getByTestId(items[0]);
 			const lastItem = getByTestId(items[items.length - 1]);
@@ -312,9 +312,9 @@ describe('Toolbar', () => {
 		const firstItem = getByTestId(items[0]);
 		const lastItem = getByTestId(items[items.length - 1]);
 		expect(firstItem).toHaveFocus();
-		await user.keyboard(`{${kbd.END}}`);
+		await user.keyboard(kbd.END);
 		expect(lastItem).toHaveFocus();
-		await user.keyboard(`{${kbd.HOME}}`);
+		await user.keyboard(kbd.HOME);
 		expect(firstItem).toHaveFocus();
 	});
 
@@ -326,7 +326,7 @@ describe('Toolbar', () => {
 			const curr = getByTestId(item);
 			curr.focus();
 			expect(curr).toHaveFocus();
-			await user.keyboard(`{${kbd.SPACE}}`);
+			await user.keyboard(kbd.SPACE);
 			expect(curr).toHaveAttribute('aria-pressed', 'true');
 			expect(curr).toHaveAttribute('data-state', 'on');
 		}
@@ -335,7 +335,7 @@ describe('Toolbar', () => {
 			const curr = getByTestId(item);
 			curr.focus();
 			expect(curr).toHaveFocus();
-			await user.keyboard(`{${kbd.SPACE}}`);
+			await user.keyboard(kbd.SPACE);
 			expect(curr).toHaveAttribute('aria-checked', 'true');
 			expect(curr).toHaveAttribute('data-state', 'on');
 		}