Repository: melt-ui/melt-ui
Pull request #770 (2023-11-25 20:44:36)

Remove undefined properties before deepEquals
Fix for issue #713 

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

Latest commit: 15c389311b3bc8979a87863254fc28476499bfa3

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.**



[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/jorri11/melt-ui/new/fix/combobox_not_selecting_#713?filename=.changeset/green-peas-glow.md&value=---%0A%22%40fake-scope%2Ffake-pkg%22%3A%20patch%0A---%0A%0A%23713%3A%20Remove%20undefined%20properties%20before%20deepEquals%0A)



Patch:
diff --git a/.changeset/afraid-chefs-talk.md b/.changeset/afraid-chefs-talk.md
new file mode 100644
index 00000000..f8edd851
--- /dev/null
+++ b/.changeset/afraid-chefs-talk.md
@@ -0,0 +1,5 @@
+---
+"@melt-ui/svelte": patch
+---
+
+Calendars: remove unnecessary cell attributes in favor of `melt` attribute
diff --git a/.changeset/cool-wolves-brush.md b/.changeset/cool-wolves-brush.md
new file mode 100644
index 00000000..d476d209
--- /dev/null
+++ b/.changeset/cool-wolves-brush.md
@@ -0,0 +1,5 @@
+---
+"@melt-ui/svelte": patch
+---
+
+Dialog: remove `aria-controls` and add `aria-modal` (closes #752)
diff --git a/.changeset/fifty-cats-collect.md b/.changeset/fifty-cats-collect.md
new file mode 100644
index 00000000..83530faa
--- /dev/null
+++ b/.changeset/fifty-cats-collect.md
@@ -0,0 +1,5 @@
+---
+"@melt-ui/svelte": patch
+---
+
+Fix: Date Pickers option store reactivity
diff --git a/.changeset/late-donuts-care.md b/.changeset/late-donuts-care.md
new file mode 100644
index 00000000..675a6782
--- /dev/null
+++ b/.changeset/late-donuts-care.md
@@ -0,0 +1,5 @@
+---
+'@melt-ui/svelte': patch
+---
+
+Combobox/Select: Fix undefined values not selecting
diff --git a/.changeset/tame-snakes-brush.md b/.changeset/tame-snakes-brush.md
new file mode 100644
index 00000000..6a5b78a3
--- /dev/null
+++ b/.changeset/tame-snakes-brush.md
@@ -0,0 +1,5 @@
+---
+"@melt-ui/svelte": patch
+---
+
+fix: label click selects first segment
diff --git a/.changeset/weak-forks-lay.md b/.changeset/weak-forks-lay.md
new file mode 100644
index 00000000..ed183b72
--- /dev/null
+++ b/.changeset/weak-forks-lay.md
@@ -0,0 +1,5 @@
+---
+"@melt-ui/svelte": patch
+---
+
+fix: Toggle when items inside of popover trigger (like SVGs) are clicked
diff --git a/src/docs/constants.ts b/src/docs/constants.ts
index 7c08c502..b173bd81 100644
--- a/src/docs/constants.ts
+++ b/src/docs/constants.ts
@@ -113,7 +113,7 @@ export const PROPS = {
 	}),
 	POSITIONING: (args: PropArgs = {}): Prop => ({
 		name: 'positioning',
-		default: args.default ?? 'positioning: "bottom"',
+		default: args.default ?? 'placement: "bottom"',
 		description: DESCRIPTIONS.FLOATING_CONFIG,
 		type: 'FloatingConfig',
 		longType: {
diff --git a/src/docs/data/builders/calendar.ts b/src/docs/data/builders/calendar.ts
index 0b55562a..ce3a10a4 100644
--- a/src/docs/data/builders/calendar.ts
+++ b/src/docs/data/builders/calendar.ts
@@ -382,10 +382,6 @@ const cell = elementSchema('cell', {
 			name: 'data-focused',
 			value: 'Present when the date is focused.',
 		},
-		{
-			name: 'data-calendar-cell',
-			value: ATTRS.MELT('cell'),
-		},
 		{
 			name: 'data-melt-calendar-cell',
 			value: ATTRS.MELT('cell'),
diff --git a/src/docs/data/builders/range-calendar.ts b/src/docs/data/builders/range-calendar.ts
index 0e3bfeb5..27fa925b 100644
--- a/src/docs/data/builders/range-calendar.ts
+++ b/src/docs/data/builders/range-calendar.ts
@@ -388,10 +388,6 @@ const cell = elementSchema('cell', {
 			name: 'data-focused',
 			value: 'Present when the date is focused.',
 		},
-		{
-			name: 'data-calendar-cell',
-			value: ATTRS.MELT('cell'),
-		},
 		{
 			name: 'data-melt-calendar-cell',
 			value: ATTRS.MELT('cell'),
diff --git a/src/docs/previews/accordion/main/tailwind/index.svelte b/src/docs/previews/accordion/main/tailwind/index.svelte
index b5c3bb94..07a10e2e 100644
--- a/src/docs/previews/accordion/main/tailwind/index.svelte
+++ b/src/docs/previews/accordion/main/tailwind/index.svelte
@@ -1,13 +1,6 @@
-<script lang="ts" context="module">
-	safeOnMount(() => {
-		console.log('mounted');
-	});
-</script>
-
 <script lang="ts">
 	import { cn } from '$docs/utils';
 	import { createAccordion, melt } from '$lib/index.js';
-	import { safeOnMount } from '$lib/internal/helpers/lifecycle';
 	import { slide } from 'svelte/transition';
 
 	const {
diff --git a/src/docs/previews/date-field/main/tailwind/index.svelte b/src/docs/previews/date-field/main/tailwind/index.svelte
index 3331bfbc..b434969f 100644
--- a/src/docs/previews/date-field/main/tailwind/index.svelte
+++ b/src/docs/previews/date-field/main/tailwind/index.svelte
@@ -38,7 +38,7 @@
 	}
 
 	[data-melt-datefield-label] {
-		@apply font-medium text-magnum-800;
+		@apply select-none font-medium text-magnum-800;
 	}
 
 	[data-melt-datefield-label][data-invalid] {
diff --git a/src/docs/previews/date-field/tut1/tailwind/index.svelte b/src/docs/previews/date-field/tut1/tailwind/index.svelte
index 21f06d97..8d12e4fa 100644
--- a/src/docs/previews/date-field/tut1/tailwind/index.svelte
+++ b/src/docs/previews/date-field/tut1/tailwind/index.svelte
@@ -39,7 +39,7 @@
 	}
 
 	[data-melt-datefield-label] {
-		@apply font-medium text-white;
+		@apply select-none font-medium text-white;
 	}
 
 	[data-melt-datefield-label][data-invalid] {
diff --git a/src/docs/previews/date-field/tut2/tailwind/index.svelte b/src/docs/previews/date-field/tut2/tailwind/index.svelte
index 509e9f48..162ef620 100644
--- a/src/docs/previews/date-field/tut2/tailwind/index.svelte
+++ b/src/docs/previews/date-field/tut2/tailwind/index.svelte
@@ -41,7 +41,7 @@
 	}
 
 	[data-melt-datefield-label] {
-		@apply font-medium text-white;
+		@apply select-none font-medium text-white;
 	}
 
 	[data-melt-datefield-label][data-invalid] {
diff --git a/src/docs/previews/date-field/tut3/tailwind/index.svelte b/src/docs/previews/date-field/tut3/tailwind/index.svelte
index 4934a0de..538efede 100644
--- a/src/docs/previews/date-field/tut3/tailwind/index.svelte
+++ b/src/docs/previews/date-field/tut3/tailwind/index.svelte
@@ -41,7 +41,7 @@
 	}
 
 	[data-melt-datefield-label] {
-		@apply font-medium text-white;
+		@apply select-none font-medium text-white;
 	}
 
 	[data-melt-datefield-label][data-invalid] {
diff --git a/src/docs/previews/date-field/tut4/tailwind/index.svelte b/src/docs/previews/date-field/tut4/tailwind/index.svelte
index 4b0c1308..89ee5dc1 100644
--- a/src/docs/previews/date-field/tut4/tailwind/index.svelte
+++ b/src/docs/previews/date-field/tut4/tailwind/index.svelte
@@ -41,7 +41,7 @@
 	}
 
 	[data-melt-datefield-label] {
-		@apply font-medium text-white;
+		@apply select-none font-medium text-white;
 	}
 
 	[data-melt-datefield-label][data-invalid] {
diff --git a/src/docs/previews/date-field/tut5/tailwind/index.svelte b/src/docs/previews/date-field/tut5/tailwind/index.svelte
index 9dfb775e..171c3d4b 100644
--- a/src/docs/previews/date-field/tut5/tailwind/index.svelte
+++ b/src/docs/previews/date-field/tut5/tailwind/index.svelte
@@ -32,7 +32,7 @@
 	}
 
 	[data-melt-datefield-label] {
-		@apply font-medium text-white;
+		@apply select-none font-medium text-white;
 	}
 
 	[data-melt-datefield-label][data-invalid] {
diff --git a/src/docs/previews/date-field/tut6/tailwind/DateField.svelte b/src/docs/previews/date-field/tut6/tailwind/DateField.svelte
index d62f1180..b424abda 100644
--- a/src/docs/previews/date-field/tut6/tailwind/DateField.svelte
+++ b/src/docs/previews/date-field/tut6/tailwind/DateField.svelte
@@ -34,7 +34,7 @@
 	}
 
 	[data-melt-datefield-label] {
-		@apply font-medium text-white;
+		@apply select-none font-medium text-white;
 	}
 
 	[data-melt-datefield-label][data-invalid] {
diff --git a/src/docs/previews/date-field/tut7/tailwind/index.svelte b/src/docs/previews/date-field/tut7/tailwind/index.svelte
index 7c4c073a..7d6ea578 100644
--- a/src/docs/previews/date-field/tut7/tailwind/index.svelte
+++ b/src/docs/previews/date-field/tut7/tailwind/index.svelte
@@ -39,7 +39,7 @@
 	}
 
 	[data-melt-datefield-label] {
-		@apply font-medium text-white;
+		@apply select-none font-medium text-white;
 	}
 
 	[data-melt-datefield-label][data-invalid] {
diff --git a/src/docs/previews/date-field/tut8/tailwind/index.svelte b/src/docs/previews/date-field/tut8/tailwind/index.svelte
index ad206a34..d81d98e2 100644
--- a/src/docs/previews/date-field/tut8/tailwind/index.svelte
+++ b/src/docs/previews/date-field/tut8/tailwind/index.svelte
@@ -36,7 +36,7 @@
 	}
 
 	[data-melt-datefield-label] {
-		@apply font-medium text-white;
+		@apply select-none font-medium text-white;
 	}
 
 	[data-melt-datefield-label][data-invalid] {
diff --git a/src/docs/previews/date-picker/defaultPh/tailwind/index.svelte b/src/docs/previews/date-picker/defaultPh/tailwind/index.svelte
index e25adde6..0c56c202 100644
--- a/src/docs/previews/date-picker/defaultPh/tailwind/index.svelte
+++ b/src/docs/previews/date-picker/defaultPh/tailwind/index.svelte
@@ -109,7 +109,7 @@
 	}
 
 	[data-melt-datefield-label] {
-		@apply font-medium text-white;
+		@apply select-none font-medium text-white;
 	}
 
 	[data-melt-datefield-label][data-invalid] {
diff --git a/src/docs/previews/date-picker/defaultValue/tailwind/index.svelte b/src/docs/previews/date-picker/defaultValue/tailwind/index.svelte
index 4e44f424..58d5f381 100644
--- a/src/docs/previews/date-picker/defaultValue/tailwind/index.svelte
+++ b/src/docs/previews/date-picker/defaultValue/tailwind/index.svelte
@@ -116,7 +116,7 @@
 	}
 
 	[data-melt-datefield-label] {
-		@apply font-medium text-white;
+		@apply select-none font-medium text-white;
 	}
 
 	[data-melt-datefield-label][data-invalid] {
diff --git a/src/docs/previews/date-picker/disabled/tailwind/index.svelte b/src/docs/previews/date-picker/disabled/tailwind/index.svelte
index 5f24d61c..e5ecbd2a 100644
--- a/src/docs/previews/date-picker/disabled/tailwind/index.svelte
+++ b/src/docs/previews/date-picker/disabled/tailwind/index.svelte
@@ -112,7 +112,7 @@
 	}
 
 	[data-melt-datefield-label] {
-		@apply font-medium text-white;
+		@apply select-none font-medium text-white;
 	}
 
 	[data-melt-datefield-label][data-invalid] {
diff --git a/src/docs/previews/date-picker/fixedWeeks/tailwind/index.svelte b/src/docs/previews/date-picker/fixedWeeks/tailwind/index.svelte
index 11b14d13..edb76af8 100644
--- a/src/docs/previews/date-picker/fixedWeeks/tailwind/index.svelte
+++ b/src/docs/previews/date-picker/fixedWeeks/tailwind/index.svelte
@@ -109,7 +109,7 @@
 	}
 
 	[data-melt-datefield-label] {
-		@apply font-medium text-white;
+		@apply select-none font-medium text-white;
 	}
 
 	[data-melt-datefield-label][data-invalid] {
diff --git a/src/docs/previews/date-picker/locale/tailwind/index.svelte b/src/docs/previews/date-picker/locale/tailwind/index.svelte
index 01d66daa..ab5e202a 100644
--- a/src/docs/previews/date-picker/locale/tailwind/index.svelte
+++ b/src/docs/previews/date-picker/locale/tailwind/index.svelte
@@ -110,7 +110,7 @@
 	}
 
 	[data-melt-datefield-label] {
-		@apply font-medium text-white;
+		@apply select-none font-medium text-white;
 	}
 
 	[data-melt-datefield-label][data-invalid] {
diff --git a/src/docs/previews/date-picker/main/tailwind/index.svelte b/src/docs/previews/date-picker/main/tailwind/index.svelte
index 7aa4f665..7cc5bc68 100644
--- a/src/docs/previews/date-picker/main/tailwind/index.svelte
+++ b/src/docs/previews/date-picker/main/tailwind/index.svelte
@@ -125,7 +125,7 @@
 	}
 
 	[data-melt-datefield-label] {
-		@apply font-medium text-magnum-800;
+		@apply select-none font-medium text-magnum-800;
 	}
 
 	[data-melt-datefield-label][data-invalid] {
diff --git a/src/docs/previews/date-picker/minMax/tailwind/index.svelte b/src/docs/previews/date-picker/minMax/tailwind/index.svelte
index 3eb2ae67..3944dbcd 100644
--- a/src/docs/previews/date-picker/minMax/tailwind/index.svelte
+++ b/src/docs/previews/date-picker/minMax/tailwind/index.svelte
@@ -113,7 +113,7 @@
 	}
 
 	[data-melt-datefield-label] {
-		@apply font-medium text-white;
+		@apply select-none font-medium text-white;
 	}
 
 	[data-melt-datefield-label][data-invalid] {
diff --git a/src/docs/previews/date-picker/multipleMonths/tailwind/index.svelte b/src/docs/previews/date-picker/multipleMonths/tailwind/index.svelte
index ac609475..2c622af1 100644
--- a/src/docs/previews/date-picker/multipleMonths/tailwind/index.svelte
+++ b/src/docs/previews/date-picker/multipleMonths/tailwind/index.svelte
@@ -110,7 +110,7 @@
 	}
 
 	[data-melt-datefield-label] {
-		@apply font-medium text-white;
+		@apply select-none font-medium text-white;
 	}
 
 	[data-melt-datefield-label][data-invalid] {
diff --git a/src/docs/previews/date-picker/pagedNav/tailwind/index.svelte b/src/docs/previews/date-picker/pagedNav/tailwind/index.svelte
index 5f6a7505..5225edcf 100644
--- a/src/docs/previews/date-picker/pagedNav/tailwind/index.svelte
+++ b/src/docs/previews/date-picker/pagedNav/tailwind/index.svelte
@@ -111,7 +111,7 @@
 	}
 
 	[data-melt-datefield-label] {
-		@apply font-medium text-white;
+		@apply select-none font-medium text-white;
 	}
 
 	[data-melt-datefield-label][data-invalid] {
diff --git a/src/docs/previews/date-picker/preventDeselect/tailwind/index.svelte b/src/docs/previews/date-picker/preventDeselect/tailwind/index.svelte
index ca5fbdf3..aa6c3e3d 100644
--- a/src/docs/previews/date-picker/preventDeselect/tailwind/index.svelte
+++ b/src/docs/previews/date-picker/preventDeselect/tailwind/index.svelte
@@ -112,7 +112,7 @@
 	}
 
 	[data-melt-datefield-label] {
-		@apply font-medium text-white;
+		@apply select-none font-medium text-white;
 	}
 
 	[data-melt-datefield-label][data-invalid] {
diff --git a/src/docs/previews/date-picker/unavailable/tailwind/index.svelte b/src/docs/previews/date-picker/unavailable/tailwind/index.svelte
index 9c178e41..4ec9f2d8 100644
--- a/src/docs/previews/date-picker/unavailable/tailwind/index.svelte
+++ b/src/docs/previews/date-picker/unavailable/tailwind/index.svelte
@@ -113,7 +113,7 @@
 	}
 
 	[data-melt-datefield-label] {
-		@apply font-medium text-white;
+		@apply select-none font-medium text-white;
 	}
 
 	[data-melt-datefield-label][data-invalid] {
diff --git a/src/docs/previews/date-picker/usingValue/tailwind/index.svelte b/src/docs/previews/date-picker/usingValue/tailwind/index.svelte
index 83056ea4..633dd937 100644
--- a/src/docs/previews/date-picker/usingValue/tailwind/index.svelte
+++ b/src/docs/previews/date-picker/usingValue/tailwind/index.svelte
@@ -118,7 +118,7 @@
 	}
 
 	[data-melt-datefield-label] {
-		@apply font-medium text-white;
+		@apply select-none font-medium text-white;
 	}
 
 	[data-melt-datefield-label][data-invalid] {
diff --git a/src/docs/previews/date-range-field/defaultPh/tailwind/index.svelte b/src/docs/previews/date-range-field/defaultPh/tailwind/index.svelte
index 3a225c8a..6805620c 100644
--- a/src/docs/previews/date-range-field/defaultPh/tailwind/index.svelte
+++ b/src/docs/previews/date-range-field/defaultPh/tailwind/index.svelte
@@ -30,7 +30,7 @@
 
 <style lang="postcss">
 	[data-melt-datefield-label] {
-		@apply font-medium text-white;
+		@apply select-none font-medium text-white;
 	}
 
 	[data-melt-datefield-label][data-invalid] {
diff --git a/src/docs/previews/date-range-field/defaultValue/tailwind/index.svelte b/src/docs/previews/date-range-field/defaultValue/tailwind/index.svelte
index fe74036d..dd050c7c 100644
--- a/src/docs/previews/date-range-field/defaultValue/tailwind/index.svelte
+++ b/src/docs/previews/date-range-field/defaultValue/tailwind/index.svelte
@@ -35,7 +35,7 @@
 
 <style lang="postcss">
 	[data-melt-datefield-label] {
-		@apply font-medium text-white;
+		@apply select-none font-medium text-white;
 	}
 
 	[data-melt-datefield-label][data-invalid] {
diff --git a/src/docs/previews/date-range-field/locales/tailwind/DateRangeField.svelte b/src/docs/previews/date-range-field/locales/tailwind/DateRangeField.svelte
index 7448925e..e6e0deb7 100644
--- a/src/docs/previews/date-range-field/locales/tailwind/DateRangeField.svelte
+++ b/src/docs/previews/date-range-field/locales/tailwind/DateRangeField.svelte
@@ -40,7 +40,7 @@
 
 <style lang="postcss">
 	[data-melt-datefield-label] {
-		@apply font-medium text-white;
+		@apply select-none font-medium text-white;
 	}
 
 	[data-melt-datefield-label][data-invalid] {
diff --git a/src/docs/previews/date-range-field/main/tailwind/index.svelte b/src/docs/previews/date-range-field/main/tailwind/index.svelte
index f60d176c..703bcb01 100644
--- a/src/docs/previews/date-range-field/main/tailwind/index.svelte
+++ b/src/docs/previews/date-range-field/main/tailwind/index.svelte
@@ -44,7 +44,7 @@
 	}
 
 	[data-melt-datefield-label] {
-		@apply font-medium text-magnum-800;
+		@apply select-none font-medium text-magnum-800;
 	}
 
 	[data-melt-datefield-label][data-invalid] {
diff --git a/src/docs/previews/date-range-field/minMax/tailwind/index.svelte b/src/docs/previews/date-range-field/minMax/tailwind/index.svelte
index 8e3e778e..67c29750 100644
--- a/src/docs/previews/date-range-field/minMax/tailwind/index.svelte
+++ b/src/docs/previews/date-range-field/minMax/tailwind/index.svelte
@@ -39,7 +39,7 @@
 
 <style lang="postcss">
 	[data-melt-datefield-label] {
-		@apply font-medium text-white;
+		@apply select-none font-medium text-white;
 	}
 
 	[data-melt-datefield-label][data-invalid] {
diff --git a/src/docs/previews/date-range-field/nowLA/tailwind/index.svelte b/src/docs/previews/date-range-field/nowLA/tailwind/index.svelte
index caff7ba5..691d09b1 100644
--- a/src/docs/previews/date-range-field/nowLA/tailwind/index.svelte
+++ b/src/docs/previews/date-range-field/nowLA/tailwind/index.svelte
@@ -31,7 +31,7 @@
 
 <style lang="postcss">
 	[data-melt-datefield-label] {
-		@apply font-medium text-white;
+		@apply select-none font-medium text-white;
 	}
 
 	[data-melt-datefield-label][data-invalid] {
diff --git a/src/docs/previews/date-range-field/nowLocalTz/tailwind/index.svelte b/src/docs/previews/date-range-field/nowLocalTz/tailwind/index.svelte
index f85c1bc1..eb29356d 100644
--- a/src/docs/previews/date-range-field/nowLocalTz/tailwind/index.svelte
+++ b/src/docs/previews/date-range-field/nowLocalTz/tailwind/index.svelte
@@ -31,7 +31,7 @@
 
 <style lang="postcss">
 	[data-melt-datefield-label] {
-		@apply font-medium text-white;
+		@apply select-none font-medium text-white;
 	}
 
 	[data-melt-datefield-label][data-invalid] {
diff --git a/src/docs/previews/date-range-field/unavailable/tailwind/index.svelte b/src/docs/previews/date-range-field/unavailable/tailwind/index.svelte
index 332a1af1..9e823fae 100644
--- a/src/docs/previews/date-range-field/unavailable/tailwind/index.svelte
+++ b/src/docs/previews/date-range-field/unavailable/tailwind/index.svelte
@@ -40,7 +40,7 @@
 
 <style lang="postcss">
 	[data-melt-datefield-label] {
-		@apply font-medium text-white;
+		@apply select-none font-medium text-white;
 	}
 
 	[data-melt-datefield-label][data-invalid] {
diff --git a/src/docs/previews/date-range-field/valueAndPh/tailwind/DateRangeField.svelte b/src/docs/previews/date-range-field/valueAndPh/tailwind/DateRangeField.svelte
index 9b9b12dc..7b510392 100644
--- a/src/docs/previews/date-range-field/valueAndPh/tailwind/DateRangeField.svelte
+++ b/src/docs/previews/date-range-field/valueAndPh/tailwind/DateRangeField.svelte
@@ -41,7 +41,7 @@
 
 <style lang="postcss">
 	[data-melt-datefield-label] {
-		@apply font-medium text-white;
+		@apply select-none font-medium text-white;
 	}
 
 	[data-melt-datefield-label][data-invalid] {
diff --git a/src/docs/previews/date-range-picker/defaultPh/tailwind/index.svelte b/src/docs/previews/date-range-picker/defaultPh/tailwind/index.svelte
index 274c9ebf..553552b3 100644
--- a/src/docs/previews/date-range-picker/defaultPh/tailwind/index.svelte
+++ b/src/docs/previews/date-range-picker/defaultPh/tailwind/index.svelte
@@ -119,7 +119,7 @@
 	}
 
 	[data-melt-datefield-label] {
-		@apply font-medium text-white;
+		@apply select-none font-medium text-white;
 	}
 
 	[data-melt-datefield-label][data-invalid] {
diff --git a/src/docs/previews/date-range-picker/defaultValue/tailwind/index.svelte b/src/docs/previews/date-range-picker/defaultValue/tailwind/index.svelte
index 29b9f0a8..526a3044 100644
--- a/src/docs/previews/date-range-picker/defaultValue/tailwind/index.svelte
+++ b/src/docs/previews/date-range-picker/defaultValue/tailwind/index.svelte
@@ -123,7 +123,7 @@
 	}
 
 	[data-melt-datefield-label] {
-		@apply font-medium text-white;
+		@apply select-none font-medium text-white;
 	}
 
 	[data-melt-datefield-label][data-invalid] {
diff --git a/src/docs/previews/date-range-picker/disabled/tailwind/index.svelte b/src/docs/previews/date-range-picker/disabled/tailwind/index.svelte
index c5b1282e..bbe4c4cf 100644
--- a/src/docs/previews/date-range-picker/disabled/tailwind/index.svelte
+++ b/src/docs/previews/date-range-picker/disabled/tailwind/index.svelte
@@ -121,7 +121,7 @@
 	}
 
 	[data-melt-datefield-label] {
-		@apply font-medium text-white;
+		@apply select-none font-medium text-white;
 	}
 
 	[data-melt-datefield-label][data-invalid] {
diff --git a/src/docs/previews/date-range-picker/fixedWeeks/tailwind/index.svelte b/src/docs/previews/date-range-picker/fixedWeeks/tailwind/index.svelte
index 9b28c98e..a356244b 100644
--- a/src/docs/previews/date-range-picker/fixedWeeks/tailwind/index.svelte
+++ b/src/docs/previews/date-range-picker/fixedWeeks/tailwind/index.svelte
@@ -119,7 +119,7 @@
 	}
 
 	[data-melt-datefield-label] {
-		@apply font-medium text-white;
+		@apply select-none font-medium text-white;
 	}
 
 	[data-melt-datefield-label][data-invalid] {
diff --git a/src/docs/previews/date-range-picker/locale/tailwind/index.svelte b/src/docs/previews/date-range-picker/locale/tailwind/index.svelte
index 49c09d63..097c90fe 100644
--- a/src/docs/previews/date-range-picker/locale/tailwind/index.svelte
+++ b/src/docs/previews/date-range-picker/locale/tailwind/index.svelte
@@ -118,7 +118,7 @@
 	}
 
 	[data-melt-datefield-label] {
-		@apply font-medium text-white;
+		@apply select-none font-medium text-white;
 	}
 
 	[data-melt-datefield-label][data-invalid] {
diff --git a/src/docs/previews/date-range-picker/main/tailwind/index.svelte b/src/docs/previews/date-range-picker/main/tailwind/index.svelte
index cad08fb9..5a576d4f 100644
--- a/src/docs/previews/date-range-picker/main/tailwind/index.svelte
+++ b/src/docs/previews/date-range-picker/main/tailwind/index.svelte
@@ -133,7 +133,7 @@
 	}
 
 	[data-melt-datefield-label] {
-		@apply font-medium text-magnum-800;
+		@apply select-none font-medium text-magnum-800;
 	}
 
 	[data-melt-datefield-label][data-invalid] {
diff --git a/src/docs/previews/date-range-picker/minMax/tailwind/index.svelte b/src/docs/previews/date-range-picker/minMax/tailwind/index.svelte
index f7d21905..8699aada 100644
--- a/src/docs/previews/date-range-picker/minMax/tailwind/index.svelte
+++ b/src/docs/previews/date-range-picker/minMax/tailwind/index.svelte
@@ -122,7 +122,7 @@
 	}
 
 	[data-melt-datefield-label] {
-		@apply font-medium text-white;
+		@apply select-none font-medium text-white;
 	}
 
 	[data-melt-datefield-label][data-invalid] {
diff --git a/src/docs/previews/date-range-picker/multipleMonths/tailwind/index.svelte b/src/docs/previews/date-range-picker/multipleMonths/tailwind/index.svelte
index 669641e5..d74f83ff 100644
--- a/src/docs/previews/date-range-picker/multipleMonths/tailwind/index.svelte
+++ b/src/docs/previews/date-range-picker/multipleMonths/tailwind/index.svelte
@@ -120,7 +120,7 @@
 	}
 
 	[data-melt-datefield-label] {
-		@apply font-medium text-white;
+		@apply select-none font-medium text-white;
 	}
 
 	[data-melt-datefield-label][data-invalid] {
diff --git a/src/docs/previews/date-range-picker/pagedNav/tailwind/index.svelte b/src/docs/previews/date-range-picker/pagedNav/tailwind/index.svelte
index 32e2ddad..09e8a658 100644
--- a/src/docs/previews/date-range-picker/pagedNav/tailwind/index.svelte
+++ b/src/docs/previews/date-range-picker/pagedNav/tailwind/index.svelte
@@ -121,7 +121,7 @@
 	}
 
 	[data-melt-datefield-label] {
-		@apply font-medium text-white;
+		@apply select-none font-medium text-white;
 	}
 
 	[data-melt-datefield-label][data-invalid] {
diff --git a/src/docs/previews/date-range-picker/unavailable/tailwind/index.svelte b/src/docs/previews/date-range-picker/unavailable/tailwind/index.svelte
index 5c97a47b..836c9f3c 100644
--- a/src/docs/previews/date-range-picker/unavailable/tailwind/index.svelte
+++ b/src/docs/previews/date-range-picker/unavailable/tailwind/index.svelte
@@ -122,7 +122,7 @@
 	}
 
 	[data-melt-datefield-label] {
-		@apply font-medium text-white;
+		@apply select-none font-medium text-white;
 	}
 
 	[data-melt-datefield-label][data-invalid] {
diff --git a/src/docs/previews/date-range-picker/usingValue/tailwind/index.svelte b/src/docs/previews/date-range-picker/usingValue/tailwind/index.svelte
index 5be9f134..665e93b0 100644
--- a/src/docs/previews/date-range-picker/usingValue/tailwind/index.svelte
+++ b/src/docs/previews/date-range-picker/usingValue/tailwind/index.svelte
@@ -124,7 +124,7 @@
 	}
 
 	[data-melt-datefield-label] {
-		@apply font-medium text-white;
+		@apply select-none font-medium text-white;
 	}
 
 	[data-melt-datefield-label][data-invalid] {
diff --git a/src/lib/builders/calendar/create.ts b/src/lib/builders/calendar/create.ts
index 6c893cf0..c3e23ce8 100644
--- a/src/lib/builders/calendar/create.ts
+++ b/src/lib/builders/calendar/create.ts
@@ -463,9 +463,6 @@ export function createCalendar<
 					'data-outside-visible-months': isOutsideVisibleMonths ? '' : undefined,
 					'data-focused': isFocusedDate ? '' : undefined,
 					tabindex: isFocusedDate ? 0 : isOutsideMonth || isDisabled ? undefined : -1,
-					// We share some selection logic between this and the range calendar
-					// so we use a common data attr that isn't a `melt` attr
-					'data-calendar-cell': '',
 				} as const;
 			};
 		},
diff --git a/src/lib/builders/date-field/create.ts b/src/lib/builders/date-field/create.ts
index 367a55a4..49a203aa 100644
--- a/src/lib/builders/date-field/create.ts
+++ b/src/lib/builders/date-field/create.ts
@@ -13,6 +13,7 @@ import {
 	isNumberString,
 	styleToString,
 	noop,
+	sleep,
 } from '$lib/internal/helpers/index.js';
 import {
 	dateStore,
@@ -22,6 +23,7 @@ import {
 	createFormatter,
 	getAnnouncer,
 	isBefore,
+	getFirstSegment,
 } from '$lib/internal/helpers/date/index.js';
 import { derived, get, writable, type Updater } from 'svelte/store';
 import {
@@ -267,6 +269,24 @@ export function createDateField(props?: CreateDateFieldProps) {
 				'data-disabled': $disabled ? '' : undefined,
 			};
 		},
+		action: (node: HTMLElement) => {
+			const unsub = executeCallbacks(
+				addMeltEventListener(node, 'click', () => {
+					const firstSegment = getFirstSegment(get(ids.field));
+					if (!firstSegment) return;
+					sleep(1).then(() => firstSegment.focus());
+				}),
+				addMeltEventListener(node, 'mousedown', (e) => {
+					if (!e.defaultPrevented && e.detail > 1) {
+						e.preventDefault();
+					}
+				})
+			);
+
+			return {
+				destroy: unsub,
+			};
+		},
 	});
 
 	const validation = builder(name('validation'), {
diff --git a/src/lib/builders/date-picker/create.ts b/src/lib/builders/date-picker/create.ts
index a745a2d6..016a9035 100644
--- a/src/lib/builders/date-picker/create.ts
+++ b/src/lib/builders/date-picker/create.ts
@@ -186,10 +186,10 @@ export function createDatePicker(props?: CreateDatePickerProps) {
 			...calendar.helpers,
 		},
 		options: {
-			...popover.options,
 			...dateFieldOptions,
 			...calendarOptions,
 			...options,
+			...popover.options,
 		},
 		ids: {
 			dateField: dateField.ids,
diff --git a/src/lib/builders/date-range-field/create.ts b/src/lib/builders/date-range-field/create.ts
index be8315d6..57490af2 100644
--- a/src/lib/builders/date-range-field/create.ts
+++ b/src/lib/builders/date-range-field/create.ts
@@ -7,6 +7,9 @@ import {
 	omit,
 	effect,
 	styleToString,
+	executeCallbacks,
+	addMeltEventListener,
+	sleep,
 } from '$lib/internal/helpers/index.js';
 import {
 	dateStore,
@@ -14,6 +17,7 @@ import {
 	getAnnouncer,
 	isBefore,
 	areAllDaysBetweenValid,
+	getFirstSegment,
 } from '$lib/internal/helpers/date/index.js';
 import { derived, get, writable } from 'svelte/store';
 import { removeDescriptionElement } from './_internal/helpers.js';
@@ -147,10 +151,30 @@ export function createDateRangeField(props?: CreateDateRangeFieldProps) {
 	);
 
 	const label = builder(name('label'), {
-		stores: [ids.label],
-		returned: ([$labelId]) => {
+		stores: [isInvalid, options.disabled, ids.label],
+		returned: ([$isInvalid, $disabled, $labelId]) => {
 			return {
 				id: $labelId,
+				'data-invalid': $isInvalid ? '' : undefined,
+				'data-disabled': $disabled ? '' : undefined,
+			};
+		},
+		action: (node: HTMLElement) => {
+			const unsub = executeCallbacks(
+				addMeltEventListener(node, 'click', () => {
+					const firstSegment = getFirstSegment(get(ids.field));
+					if (!firstSegment) return;
+					sleep(1).then(() => firstSegment.focus());
+				}),
+				addMeltEventListener(node, 'mousedown', (e) => {
+					if (!e.defaultPrevented && e.detail > 1) {
+						e.preventDefault();
+					}
+				})
+			);
+
+			return {
+				destroy: unsub,
 			};
 		},
 	});
diff --git a/src/lib/builders/date-range-picker/create.ts b/src/lib/builders/date-range-picker/create.ts
index 78c41e29..a80118d3 100644
--- a/src/lib/builders/date-range-picker/create.ts
+++ b/src/lib/builders/date-range-picker/create.ts
@@ -189,10 +189,10 @@ export function createDateRangePicker(props?: CreateDateRangePickerProps) {
 			...calendar.helpers,
 		},
 		options: {
-			...popover.options,
 			...rangeFieldOptions,
 			...rangeCalendarOptions,
 			...options,
+			...popover.options,
 		},
 		ids: {
 			rangeField: rangeField.ids,
diff --git a/src/lib/builders/dialog/create.ts b/src/lib/builders/dialog/create.ts
index a2e7c4d2..8ce36f3a 100644
--- a/src/lib/builders/dialog/create.ts
+++ b/src/lib/builders/dialog/create.ts
@@ -120,12 +120,11 @@ export function createDialog(props?: CreateDialogProps) {
 	});
 
 	const trigger = builder(name('trigger'), {
-		stores: [open, ids.content],
-		returned: ([$open, $contentId]) => {
+		stores: [open],
+		returned: ([$open]) => {
 			return {
 				'aria-haspopup': 'dialog',
 				'aria-expanded': $open,
-				'aria-controls': $contentId,
 				type: 'button',
 			} as const;
 		},
@@ -190,6 +189,7 @@ export function createDialog(props?: CreateDialogProps) {
 				role: get(role),
 				'aria-describedby': $descriptionId,
 				'aria-labelledby': $titleId,
+				'aria-modal': $isVisible ? 'true' : undefined,
 				'data-state': $isVisible ? 'open' : 'closed',
 				tabindex: -1,
 				hidden: $isVisible ? undefined : true,
diff --git a/src/lib/builders/listbox/create.ts b/src/lib/builders/listbox/create.ts
index 8f6b3062..082ff338 100644
--- a/src/lib/builders/listbox/create.ts
+++ b/src/lib/builders/listbox/create.ts
@@ -23,6 +23,7 @@ import {
 	isHTMLButtonElement,
 	isHTMLElement,
 	isHTMLInputElement,
+	isObject,
 	kbd,
 	last,
 	next,
@@ -32,6 +33,7 @@ import {
 	prev,
 	removeHighlight,
 	removeScroll,
+	stripValues,
 	styleToString,
 	toWritableStores,
 	toggle,
@@ -235,6 +237,9 @@ export function createListbox<
 			if (Array.isArray($selected)) {
 				return $selected.some((o) => deepEqual(o.value, value));
 			}
+			if (isObject(value)) {
+				return deepEqual($selected?.value, stripValues(value, undefined, true));
+			}
 			return deepEqual($selected?.value, value);
 		};
 	});
@@ -546,13 +551,11 @@ export function createListbox<
 	});
 
 	const option = builder(name('option'), {
-		stores: [selected],
+		stores: [isSelected],
 		returned:
-			([$selected]) =>
+			([$isSelected]) =>
 			(props: ListboxOptionProps<Value>) => {
-				const selected = Array.isArray($selected)
-					? $selected.some((o) => deepEqual(o.value, props.value))
-					: deepEqual($selected?.value, props.value);
+				const selected = $isSelected(props.value);
 
 				return {
 					'data-value': JSON.stringify(props.value),
diff --git a/src/lib/builders/popover/create.ts b/src/lib/builders/popover/create.ts
index 29cd6ceb..fb5cab2d 100644
--- a/src/lib/builders/popover/create.ts
+++ b/src/lib/builders/popover/create.ts
@@ -140,11 +140,7 @@ export function createPopover(args?: CreatePopoverProps) {
 								  },
 							clickOutside: $closeOnOutsideClick
 								? {
-										handler: (e) => {
-											const target = e.target;
-											if (isElement(target) && target.id === get(ids.trigger)) return;
-											handleClose();
-										},
+										handler: handleClickOutside,
 								  }
 								: null,
 							escapeKeydown: $closeOnEscape
@@ -182,6 +178,16 @@ export function createPopover(args?: CreatePopoverProps) {
 		}
 	}
 
+	function handleClickOutside(e: PointerEvent) {
+		const target = e.target;
+		const triggerEl = document.getElementById(get(ids.trigger));
+
+		if (triggerEl && isElement(target)) {
+			if (target === triggerEl || triggerEl.contains(target)) return;
+		}
+		handleClose();
+	}
+
 	const trigger = builder(name('trigger'), {
 		stores: [open, ids.content, ids.trigger],
 		returned: ([$open, $contentId, $triggerId]) => {
diff --git a/src/lib/builders/range-calendar/create.ts b/src/lib/builders/range-calendar/create.ts
index a9a54d6d..04e9af0e 100644
--- a/src/lib/builders/range-calendar/create.ts
+++ b/src/lib/builders/range-calendar/create.ts
@@ -478,9 +478,6 @@ export function createRangeCalendar<T extends DateValue = DateValue>(
 					'data-focused': isFocusedDate ? '' : undefined,
 					'data-highlighted': isHighlighted ? '' : undefined,
 					tabindex: isFocusedDate ? 0 : isOutsideMonth || isDisabled ? undefined : -1,
-					// We share selection logic between this & the calendar builder
-					// so we aren't using the `melt` attr to select
-					'data-calendar-cell': '',
 				} as const;
 			};
 		},
diff --git a/src/lib/internal/helpers/date/calendar.ts b/src/lib/internal/helpers/date/calendar.ts
index 2aa32538..4d595534 100644
--- a/src/lib/internal/helpers/date/calendar.ts
+++ b/src/lib/internal/helpers/date/calendar.ts
@@ -159,7 +159,7 @@ export function createMonths(props: SetMonthProps) {
 export function getSelectableCells(calendarId: string) {
 	const node = document.getElementById(calendarId);
 	if (!node) return [];
-	const selectableSelector = `[data-calendar-cell]:not([data-disabled]):not([data-outside-visible-months])`;
+	const selectableSelector = `[data-melt-calendar-cell]:not([data-disabled]):not([data-outside-visible-months])`;
 
 	return Array.from(node.querySelectorAll(selectableSelector)).filter((el): el is HTMLElement =>
 		isHTMLElement(el)
diff --git a/src/lib/internal/helpers/date/field.ts b/src/lib/internal/helpers/date/field.ts
index 2c0e9468..01beca68 100644
--- a/src/lib/internal/helpers/date/field.ts
+++ b/src/lib/internal/helpers/date/field.ts
@@ -104,3 +104,11 @@ export function getSegments(id: string) {
 	);
 	return segments;
 }
+
+/**
+ * Get the first interactive segment within the field identified by the provided ID.
+ */
+export function getFirstSegment(id: string) {
+	const segments = getSegments(id);
+	return segments[0];
+}
diff --git a/src/lib/internal/helpers/is.ts b/src/lib/internal/helpers/is.ts
index 43fb27d5..e75bdc96 100644
--- a/src/lib/internal/helpers/is.ts
+++ b/src/lib/internal/helpers/is.ts
@@ -61,3 +61,7 @@ export function isNumberString(value: string) {
 	if (isNaN(parseInt(value))) return false;
 	return true;
 }
+
+export function isObject(value: unknown): value is Record<string, unknown> {
+	return value !== null && typeof value === 'object';
+}
diff --git a/src/lib/internal/helpers/object.ts b/src/lib/internal/helpers/object.ts
index f1828ced..26d49f66 100644
--- a/src/lib/internal/helpers/object.ts
+++ b/src/lib/internal/helpers/object.ts
@@ -1,4 +1,5 @@
 import type { ValueOf } from '$lib/internal/types.js';
+import { dequal } from 'dequal';
 
 export function omit<T extends Record<string, unknown>, K extends keyof T>(
 	obj: T,
@@ -12,3 +13,37 @@ export function omit<T extends Record<string, unknown>, K extends keyof T>(
 	}
 	return result;
 }
+
+type StrippedKeys<T extends Record<string, unknown>, ToStrip> = {
+	[K in keyof T]: T[K] extends ToStrip ? never : K;
+};
+
+type StripValues<T extends Record<string, unknown>, ToStrip> = {
+	[K in StrippedKeys<T, ToStrip>[keyof T]]: T[K];
+};
+
+type StripValuesRecursive<T extends Record<string, unknown>, ToStrip> = {
+	[K in StrippedKeys<T, ToStrip>[keyof T]]: T[K] extends Record<string, unknown>
+		? StripValuesRecursive<T[K], ToStrip>
+		: T[K];
+};
+
+export function stripValues<T extends Record<string, unknown>, ToStrip>(
+	inputObject: T,
+	toStrip: ToStrip,
+	recursive: false
+): StripValues<T, ToStrip>;
+export function stripValues<T extends Record<string, unknown>, ToStrip>(
+	inputObject: T,
+	toStrip: ToStrip,
+	recursive: true
+): StripValuesRecursive<T, ToStrip>;
+export function stripValues<T extends Record<string, unknown>, ToStrip>(
+	inputObject: T,
+	toStrip: ToStrip,
+	recursive: boolean
+) {
+	return Object.fromEntries(
+		Object.entries(inputObject).filter(([_, value]) => !dequal(value, toStrip))
+	) as typeof recursive extends true ? StripValuesRecursive<T, ToStrip> : StripValues<T, ToStrip>;
+}
diff --git a/src/lib/shared/index.ts b/src/lib/shared/index.ts
index 2069250e..b9513b12 100644
--- a/src/lib/shared/index.ts
+++ b/src/lib/shared/index.ts
@@ -4,7 +4,8 @@
  * use, they should be exported from this file to prevent conflicts
  * with other builders that may export the same types or functions.
  */
-import type { Granularity, Matcher, DateRange, Month } from '$lib/internal/helpers/date';
+import type { SegmentPart } from '$lib/builders/date-field/_internal/types.js';
+import type { Granularity, Matcher, DateRange, Month } from '$lib/internal/helpers/date/index.js';
 import type { FocusProp, FocusTarget } from '$lib/internal/helpers/index.js';
 
-export type { Granularity, FocusProp, FocusTarget, Matcher, DateRange, Month };
+export type { Granularity, FocusProp, FocusTarget, Matcher, DateRange, Month, SegmentPart };


Test patch:
diff --git a/src/tests/calendar/Calendar.spec.ts b/src/tests/calendar/Calendar.spec.ts
index f8968705..1bad214d 100644
--- a/src/tests/calendar/Calendar.spec.ts
+++ b/src/tests/calendar/Calendar.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';
@@ -8,6 +8,7 @@ import { CalendarDate, CalendarDateTime, toZoned, type DateValue } from '@intern
 import { writable } from 'svelte/store';
 import { tick } from 'svelte';
 import CalendarMultiTest from './CalendarMultiTest.svelte';
+import type { CreateCalendarProps } from '$lib/builders/index.js';
 
 const calendarDate = new CalendarDate(1980, 1, 20);
 const calendarDateTime = new CalendarDateTime(1980, 1, 20, 12, 30, 0, 0);
@@ -17,6 +18,30 @@ const controlledCalendarDate = writable<DateValue | undefined>(calendarDate);
 const controlledCalendarDateTime = writable<DateValue | undefined>(calendarDateTime);
 const controlledZonedDateTime = writable<DateValue | undefined>(zonedDateTime);
 
+function setup(props: CreateCalendarProps = {}) {
+	const user = userEvent.setup();
+	const returned = render(CalendarTest, props);
+	const calendar = returned.getByTestId('calendar');
+	expect(calendar).toBeVisible();
+	return {
+		...returned,
+		user,
+		calendar,
+	};
+}
+
+function setupMulti(props: CreateCalendarProps<true> = {}) {
+	const user = userEvent.setup();
+	const returned = render(CalendarMultiTest, props);
+	const calendar = returned.getByTestId('calendar');
+	expect(calendar).toBeVisible();
+	return {
+		...returned,
+		user,
+		calendar,
+	};
+}
+
 describe('Calendar', () => {
 	describe('Accessibility', () => {
 		test('has no accessibility violations', async () => {
@@ -26,28 +51,24 @@ describe('Calendar', () => {
 		});
 	});
 	test('populated with defaultValue - CalendarDate', async () => {
-		const { getByTestId, container } = render(CalendarTest, {
+		const { getByTestId, calendar } = setup({
 			defaultValue: calendarDate,
 		});
 
-		const calendar = getByTestId('calendar');
 		expect(calendar).toBeVisible();
 
-		const selectedDay = container.querySelector('[data-selected]');
+		const selectedDay = calendar.querySelector('[data-selected]');
 		expect(selectedDay).toHaveTextContent(String(calendarDate.day));
 
 		const heading = getByTestId('heading');
 		expect(heading).toHaveTextContent('January 1980');
 	});
 	test('populated with defaultValue - CalendarDateTime', async () => {
-		const { getByTestId, container } = render(CalendarTest, {
+		const { getByTestId, calendar } = setup({
 			defaultValue: calendarDateTime,
 		});
 
-		const calendar = getByTestId('calendar');
-		expect(calendar).toBeVisible();
-
-		const selectedDay = container.querySelector('[data-selected]');
+		const selectedDay = calendar.querySelector('[data-selected]');
 		expect(selectedDay).toHaveTextContent(String(calendarDateTime.day));
 
 		const heading = getByTestId('heading');
@@ -55,14 +76,11 @@ describe('Calendar', () => {
 	});
 
 	test('populated with defaultValue - ZonedDateTime', async () => {
-		const { getByTestId, container } = render(CalendarTest, {
+		const { getByTestId, calendar } = setup({
 			defaultValue: zonedDateTime,
 		});
 
-		const calendar = getByTestId('calendar');
-		expect(calendar).toBeVisible();
-
-		const selectedDay = container.querySelector('[data-selected]');
+		const selectedDay = calendar.querySelector('[data-selected]');
 		expect(selectedDay).toHaveTextContent(String(zonedDateTime.day));
 
 		const heading = getByTestId('heading');
@@ -70,14 +88,11 @@ describe('Calendar', () => {
 	});
 
 	test('populated with controlled value - CalendarDate', async () => {
-		const { getByTestId, container } = render(CalendarTest, {
+		const { getByTestId, calendar } = setup({
 			value: controlledCalendarDate,
 		});
 
-		const calendar = getByTestId('calendar');
-		expect(calendar).toBeVisible();
-
-		const selectedDay = container.querySelector('[data-selected]');
+		const selectedDay = calendar.querySelector('[data-selected]');
 		expect(selectedDay).toHaveTextContent(String(calendarDate.day));
 
 		const heading = getByTestId('heading');
@@ -85,14 +100,11 @@ describe('Calendar', () => {
 	});
 
 	test('populated with controlled value - CalendarDateTime', async () => {
-		const { getByTestId, container } = render(CalendarTest, {
+		const { getByTestId, calendar } = setup({
 			value: controlledCalendarDateTime,
 		});
 
-		const calendar = getByTestId('calendar');
-		expect(calendar).toBeVisible();
-
-		const selectedDay = container.querySelector('[data-selected]');
+		const selectedDay = calendar.querySelector('[data-selected]');
 		expect(selectedDay).toHaveTextContent(String(calendarDateTime.day));
 
 		const heading = getByTestId('heading');
@@ -100,14 +112,11 @@ describe('Calendar', () => {
 	});
 
 	test('populated with controlled value - ZonedDateTime', async () => {
-		const { getByTestId, container } = render(CalendarTest, {
+		const { getByTestId, calendar } = setup({
 			value: controlledZonedDateTime,
 		});
 
-		const calendar = getByTestId('calendar');
-		expect(calendar).toBeVisible();
-
-		const selectedDay = container.querySelector('[data-selected]');
+		const selectedDay = calendar.querySelector('[data-selected]');
 		expect(selectedDay).toHaveTextContent(String(zonedDateTime.day));
 
 		const heading = getByTestId('heading');
@@ -115,14 +124,10 @@ describe('Calendar', () => {
 	});
 
 	test('month navigation', async () => {
-		const user = userEvent.setup();
-		const { getByTestId } = render(CalendarTest, {
+		const { getByTestId, user } = setup({
 			defaultValue: zonedDateTime,
 		});
 
-		const calendar = getByTestId('calendar');
-		expect(calendar).toBeVisible();
-
 		const heading = getByTestId('heading');
 		expect(heading).toHaveTextContent('January 1980');
 
@@ -140,15 +145,11 @@ describe('Calendar', () => {
 	});
 
 	test('allow deselection', async () => {
-		const user = userEvent.setup();
-		const { getByTestId, container, queryByTestId } = render(CalendarTest, {
+		const { calendar, queryByTestId, user } = setup({
 			defaultValue: zonedDateTime,
 		});
 
-		const calendar = getByTestId('calendar');
-		expect(calendar).toBeVisible();
-
-		const selectedDay = container.querySelector('[data-selected]') as HTMLElement;
+		const selectedDay = calendar.querySelector('[data-selected]') as HTMLElement;
 		expect(selectedDay).toHaveTextContent(String(zonedDateTime.day));
 
 		await user.click(selectedDay);
@@ -159,13 +160,10 @@ describe('Calendar', () => {
 	});
 
 	test('selection with mouse', async () => {
-		const user = userEvent.setup();
-		const { getByTestId } = render(CalendarTest, {
+		const { getByTestId, user } = setup({
 			defaultPlaceholder: zonedDateTime,
 		});
 
-		const calendar = getByTestId('calendar');
-		expect(calendar).toBeVisible();
 		const secondDayInMonth = getByTestId('month-0-date-2');
 		await user.click(secondDayInMonth);
 		expect(secondDayInMonth).toHaveAttribute('data-selected');
@@ -176,22 +174,19 @@ describe('Calendar', () => {
 	});
 
 	test('selection with keyboard', async () => {
-		const user = userEvent.setup();
-		const { getByTestId } = render(CalendarTest, {
+		const { getByTestId, user } = setup({
 			defaultPlaceholder: zonedDateTime,
 		});
 
-		const calendar = getByTestId('calendar');
-		expect(calendar).toBeVisible();
 		const secondDayInMonth = getByTestId('month-0-date-2');
 		secondDayInMonth.focus();
-		await user.keyboard(`{${kbd.SPACE}}`);
+		await user.keyboard(kbd.SPACE);
 		expect(secondDayInMonth).toHaveAttribute('data-selected');
 		const newDate = zonedDateTime.set({ day: 2 });
 		const insideValue = getByTestId('inside-value');
 		expect(insideValue).toHaveTextContent(newDate.toString());
-		await user.keyboard(`{${kbd.ARROW_RIGHT}}`);
-		await user.keyboard(`{${kbd.ENTER}}`);
+		await user.keyboard(kbd.ARROW_RIGHT);
+		await user.keyboard(kbd.ENTER);
 
 		const thirdDayInMonth = getByTestId('month-0-date-3');
 		expect(thirdDayInMonth).toHaveAttribute('data-selected');
@@ -201,16 +196,12 @@ describe('Calendar', () => {
 	});
 
 	test('should display multiple months with numberOfMonths prop', async () => {
-		const user = userEvent.setup();
-		const { getByTestId, container } = render(CalendarTest, {
+		const { getByTestId, calendar, user } = setup({
 			defaultValue: calendarDateTime,
 			numberOfMonths: 2,
 		});
 
-		const calendar = getByTestId('calendar');
-		expect(calendar).toBeVisible();
-
-		const selectedDay = container.querySelector('[data-selected]');
+		const selectedDay = calendar.querySelector('[data-selected]');
 		expect(selectedDay).toHaveTextContent(String(calendarDateTime.day));
 
 		const heading = getByTestId('heading');
@@ -243,17 +234,13 @@ describe('Calendar', () => {
 	});
 
 	test('multiple months (paged navigation)', async () => {
-		const user = userEvent.setup();
-		const { getByTestId, container } = render(CalendarTest, {
+		const { getByTestId, calendar, user } = setup({
 			defaultValue: calendarDateTime,
 			numberOfMonths: 2,
 			pagedNavigation: true,
 		});
 
-		const calendar = getByTestId('calendar');
-		expect(calendar).toBeVisible();
-
-		const selectedDay = container.querySelector('[data-selected]');
+		const selectedDay = calendar.querySelector('[data-selected]');
 		expect(selectedDay).toHaveTextContent(String(calendarDateTime.day));
 
 		const heading = getByTestId('heading');
@@ -287,7 +274,7 @@ describe('Calendar', () => {
 	test('fixedWeeks always renders 6 weeks', async () => {
 		const valueStore = writable(calendarDate);
 
-		const { getByTestId, queryByTestId } = render(CalendarTest, {
+		const { getByTestId, queryByTestId, user } = setup({
 			value: valueStore,
 			fixedWeeks: true,
 		});
@@ -296,21 +283,21 @@ describe('Calendar', () => {
 		const prevButton = getByTestId('prev-button');
 
 		for (let i = 0; i < 12; i++) {
-			await userEvent.click(nextButton);
+			await user.click(nextButton);
 			expect(queryByTestId('week-6')).not.toBeNull();
 		}
 
 		valueStore.set(calendarDate);
 
 		for (let i = 0; i < 12; i++) {
-			await userEvent.click(prevButton);
+			await user.click(prevButton);
 			expect(queryByTestId('week-6')).not.toBeNull();
 		}
 	});
 	test('controlled value should update selected value', async () => {
 		const valueStore = writable<DateValue | undefined>(undefined);
 
-		const { getByTestId } = render(CalendarTest, {
+		const { getByTestId } = setup({
 			value: valueStore,
 		});
 
@@ -328,7 +315,7 @@ describe('Calendar', () => {
 
 	test('controlled placeholder should change view', async () => {
 		const placeholderStore = writable<DateValue>(calendarDate);
-		const { getByTestId } = render(CalendarTest, {
+		const { getByTestId } = setup({
 			defaultValue: calendarDate,
 			placeholder: placeholderStore,
 		});
@@ -347,50 +334,50 @@ describe('Calendar', () => {
 	});
 
 	test('calendar does not navigate before minValue', async () => {
-		const { getByTestId } = render(CalendarTest, {
+		const { getByTestId, user } = setup({
 			defaultValue: calendarDate,
 			minValue: new CalendarDate(1979, 11, 25),
 		});
 
 		const prevButton = getByTestId('prev-button');
-		await userEvent.click(prevButton);
+		await user.click(prevButton);
 		const heading = getByTestId('heading');
 		expect(heading).toHaveTextContent('December 1979');
 		expect(prevButton).not.toHaveAttribute('aria-disabled', 'true');
 		expect(prevButton).not.toHaveAttribute('data-disabled');
-		await userEvent.click(prevButton);
+		await user.click(prevButton);
 		expect(heading).toHaveTextContent('November 1979');
 
 		expect(prevButton).toHaveAttribute('aria-disabled', 'true');
 		expect(prevButton).toHaveAttribute('data-disabled');
 
-		await userEvent.click(prevButton);
+		await user.click(prevButton);
 		expect(heading).toHaveTextContent('November 1979');
 	});
 
 	test('calendar does not navigate after maxValue', async () => {
-		const { getByTestId } = render(CalendarTest, {
+		const { getByTestId, user } = setup({
 			defaultValue: calendarDate,
 			maxValue: new CalendarDate(1980, 4, 1),
 		});
 
 		const nextButton = getByTestId('next-button');
-		await userEvent.click(nextButton);
+		await user.click(nextButton);
 		const heading = getByTestId('heading');
 		expect(heading).toHaveTextContent('February 1980');
-		await userEvent.click(nextButton);
+		await user.click(nextButton);
 		expect(heading).toHaveTextContent('March 1980');
 
 		expect(nextButton).not.toHaveAttribute('aria-disabled', 'true');
 		expect(nextButton).not.toHaveAttribute('data-disabled');
 
-		await userEvent.click(nextButton);
+		await user.click(nextButton);
 		expect(heading).toHaveTextContent('April 1980');
 
 		expect(nextButton).toHaveAttribute('aria-disabled', 'true');
 		expect(nextButton).toHaveAttribute('data-disabled');
 
-		await userEvent.click(nextButton);
+		await user.click(nextButton);
 		expect(heading).toHaveTextContent('April 1980');
 	});
 
@@ -398,7 +385,7 @@ describe('Calendar', () => {
 		const day1 = new CalendarDate(1980, 1, 2);
 		const day2 = new CalendarDate(1980, 1, 5);
 
-		const { getByTestId, container } = render(CalendarMultiTest, {
+		const { getByTestId, container } = setupMulti({
 			defaultValue: [day1, day2],
 		});
 
@@ -434,21 +421,18 @@ describe('Calendar', () => {
 		const day1 = new CalendarDate(1980, 1, 2);
 		const day2 = new CalendarDate(1980, 1, 5);
 
-		const { getByTestId, container } = render(CalendarMultiTest, {
+		const { calendar, user } = setupMulti({
 			defaultValue: [day1, day2],
 		});
 
-		const calendar = getByTestId('calendar');
-		expect(calendar).toBeVisible();
-
-		const selectedDays = container.querySelectorAll('[data-selected]');
+		const selectedDays = calendar.querySelectorAll('[data-selected]');
 		expect(selectedDays).toHaveLength(2);
 
 		expect(selectedDays[0]).toHaveTextContent(String(day1.day));
 		expect(selectedDays[1]).toHaveTextContent(String(day2.day));
 
-		await userEvent.click(selectedDays[0]);
-		const selectedDaysAfterClick = container.querySelectorAll('[data-selected]');
+		await user.click(selectedDays[0]);
+		const selectedDaysAfterClick = calendar.querySelectorAll('[data-selected]');
 		expect(selectedDaysAfterClick).toHaveLength(1);
 		expect(selectedDaysAfterClick[0]).toHaveTextContent(String(day2.day));
 	});
@@ -457,22 +441,19 @@ describe('Calendar', () => {
 		const day1 = new CalendarDate(1980, 1, 2);
 		const day2 = new CalendarDate(1980, 1, 5);
 
-		const { getByTestId, container } = render(CalendarMultiTest, {
+		const { calendar, user } = setupMulti({
 			defaultValue: [day1, day2],
 			preventDeselect: true,
 		});
 
-		const calendar = getByTestId('calendar');
-		expect(calendar).toBeVisible();
-
-		const selectedDays = container.querySelectorAll('[data-selected]');
+		const selectedDays = calendar.querySelectorAll('[data-selected]');
 		expect(selectedDays).toHaveLength(2);
 
 		expect(selectedDays[0]).toHaveTextContent(String(day1.day));
 		expect(selectedDays[1]).toHaveTextContent(String(day2.day));
 
-		await userEvent.click(selectedDays[0]);
-		const selectedDaysAfterClick = container.querySelectorAll('[data-selected]');
+		await user.click(selectedDays[0]);
+		const selectedDaysAfterClick = calendar.querySelectorAll('[data-selected]');
 		expect(selectedDaysAfterClick).toHaveLength(2);
 		expect(selectedDaysAfterClick[0]).toHaveTextContent(String(day1.day));
 		expect(selectedDaysAfterClick[1]).toHaveTextContent(String(day2.day));
@@ -482,7 +463,7 @@ describe('Calendar', () => {
 		const day1 = new CalendarDate(1980, 1, 2);
 		const day2 = new CalendarDate(1980, 1, 5);
 
-		const { getByTestId, container } = render(CalendarMultiTest, {
+		const { getByTestId, container } = setupMulti({
 			defaultValue: [day1, day2],
 		});
 
@@ -495,7 +476,7 @@ describe('Calendar', () => {
 
 	test('overridable with multiple', async () => {
 		const day1 = new CalendarDate(1980, 1, 10);
-		const { getByTestId, container } = render(CalendarMultiTest, {
+		const { getByTestId, calendar, user } = setupMulti({
 			defaultValue: [day1],
 			onValueChange: ({ curr, next }) => {
 				if (next && next.length > 2) {
@@ -506,49 +487,46 @@ describe('Calendar', () => {
 			},
 		});
 
-		const calendar = getByTestId('calendar');
-		expect(calendar).toBeVisible();
-
-		const selectedDays = container.querySelectorAll('[data-selected]');
+		const selectedDays = calendar.querySelectorAll('[data-selected]');
 		expect(selectedDays).toHaveLength(1);
 
 		const thirdDayInMonth = getByTestId('month-0-date-3');
 
-		await userEvent.click(thirdDayInMonth);
+		await user.click(thirdDayInMonth);
 
-		const selectedDaysAfterClick = container.querySelectorAll('[data-selected]');
+		const selectedDaysAfterClick = calendar.querySelectorAll('[data-selected]');
 		expect(selectedDaysAfterClick).toHaveLength(2);
 
 		const fifthDayInMonth = getByTestId('month-0-date-5');
 
-		await userEvent.click(fifthDayInMonth);
+		await user.click(fifthDayInMonth);
 
-		const selectedDaysAfterClick2 = container.querySelectorAll('[data-selected]');
+		const selectedDaysAfterClick2 = calendar.querySelectorAll('[data-selected]');
 		expect(selectedDaysAfterClick2).toHaveLength(2);
 	});
 
 	test('overridable with single', async () => {
 		const overrideDay = new CalendarDate(1980, 1, 25);
 
-		const { getByTestId, container } = render(CalendarTest, {
+		const { getByTestId, calendar, user } = setup({
 			defaultValue: calendarDate,
 			onValueChange: () => {
 				return overrideDay;
 			},
 		});
 
-		const selectedDay = container.querySelector('[data-selected]');
+		const selectedDay = calendar.querySelector('[data-selected]');
 		expect(selectedDay).toHaveTextContent(String(calendarDate.day));
 
 		const thirdDayInMonth = getByTestId('month-0-date-3');
-		await userEvent.click(thirdDayInMonth);
+		await user.click(thirdDayInMonth);
 
-		const selectedDayAfterClick = container.querySelector('[data-selected]');
+		const selectedDayAfterClick = calendar.querySelector('[data-selected]');
 		expect(selectedDayAfterClick).toHaveTextContent(String(overrideDay.day));
 	});
 
 	test('unavailable dates behavior', async () => {
-		const { getByTestId } = render(CalendarTest, {
+		const { getByTestId, user } = setup({
 			defaultPlaceholder: calendarDate,
 			isDateUnavailable: (date) => {
 				return date.day === 3;
@@ -558,12 +536,12 @@ describe('Calendar', () => {
 		const thirdDayInMonth = getByTestId('month-0-date-3');
 		expect(thirdDayInMonth).toHaveAttribute('data-unavailable');
 		expect(thirdDayInMonth).toHaveAttribute('aria-disabled', 'true');
-		await userEvent.click(thirdDayInMonth);
+		await user.click(thirdDayInMonth);
 		expect(thirdDayInMonth).not.toHaveAttribute('data-selected');
 	});
 
 	test('disabled prop prevents calendar focus & interaction', async () => {
-		const { getByTestId } = render(CalendarTest, {
+		const { getByTestId, user } = setup({
 			defaultPlaceholder: calendarDate,
 			disabled: true,
 		});
@@ -576,12 +554,12 @@ describe('Calendar', () => {
 		expect(grid).toHaveAttribute('data-disabled');
 
 		const firstDayOfMonth = getByTestId('month-0-date-1');
-		await userEvent.click(firstDayOfMonth);
+		await user.click(firstDayOfMonth);
 		expect(firstDayOfMonth).not.toHaveFocus();
 	});
 
 	test('readonly prop prevents selecting dates but allows focus', async () => {
-		const { getByTestId } = render(CalendarTest, {
+		const { getByTestId, user } = setup({
 			defaultPlaceholder: calendarDate,
 			readonly: true,
 		});
@@ -594,7 +572,7 @@ describe('Calendar', () => {
 		expect(grid).toHaveAttribute('data-readonly');
 
 		const firstDayOfMonth = getByTestId('month-0-date-1');
-		await userEvent.click(firstDayOfMonth);
+		await user.click(firstDayOfMonth);
 		expect(firstDayOfMonth).toHaveFocus();
 		expect(firstDayOfMonth).not.toHaveAttribute('data-selected');
 	});
diff --git a/src/tests/combobox/Combobox.spec.ts b/src/tests/combobox/Combobox.spec.ts
new file mode 100644
index 00000000..f3fe0b3f
--- /dev/null
+++ b/src/tests/combobox/Combobox.spec.ts
@@ -0,0 +1,131 @@
+import { act, render } from '@testing-library/svelte';
+import userEvent from '@testing-library/user-event';
+import { axe } from 'jest-axe';
+import { describe } from 'vitest';
+import { testKbd as kbd } from '../utils';
+import ComboboxTest from './ComboboxTest.svelte';
+import type { ComboboxOptionProps } from '$lib';
+
+const options: ComboboxOptionProps[] = [
+	{
+		label: 'Kentaro Miura',
+		value: 'Kentaro Miura',
+	},
+	{
+		label: 'ONE',
+		value: 'ONE',
+	},
+];
+
+const OPEN_KEYS = [kbd.SPACE, kbd.A];
+
+describe('Combobox', () => {
+	test('No accessibility violations', async () => {
+		const { container } = render(ComboboxTest);
+		expect(await axe(container)).toHaveNoViolations();
+	});
+
+	test('Opens/Closes when input is clicked', async () => {
+		const { getByTestId } = render(ComboboxTest);
+		const input = getByTestId('input');
+		const menu = getByTestId('menu');
+		const user = userEvent.setup();
+
+		expect(menu).not.toBeVisible();
+		await user.click(input);
+		expect(getByTestId('menu')).toBeVisible();
+
+		await user.click(input);
+		expect(menu).not.toBeVisible();
+	});
+
+	test.each(OPEN_KEYS)('Opens when %s is pressed', async (key) => {
+		const { getByTestId } = render(ComboboxTest);
+		const trigger = getByTestId('input');
+		const menu = getByTestId('menu');
+		const user = userEvent.setup();
+
+		expect(menu).not.toBeVisible();
+		await act(() => trigger.focus());
+		await user.keyboard(key);
+		expect(menu).toBeVisible();
+	});
+
+	test('Selects item when clicked', async () => {
+		const { getByTestId } = render(ComboboxTest, { options });
+		const input = getByTestId('input');
+		const menu = getByTestId('menu');
+		const user = userEvent.setup();
+
+		expect(input).not.toHaveValue(options[0].label);
+
+		expect(menu).not.toBeVisible();
+		await user.click(input);
+		expect(menu).toBeVisible();
+
+		const firstItem = menu.querySelector('[data-melt-combobox-option]');
+		if (!firstItem) throw new Error('No option found');
+		await user.click(firstItem);
+
+		expect(menu).not.toBeVisible();
+		expect(input).toHaveValue(options[0].label);
+
+		await user.click(input);
+		expect(menu).toBeVisible();
+
+		const secondItem = menu.querySelectorAll('[data-melt-combobox-option]')[1];
+		if (!secondItem) throw new Error('No option found');
+		await user.click(secondItem);
+
+		expect(menu).not.toBeVisible();
+		expect(input).toHaveValue(options[1].label);
+	});
+
+	test('Shows correct label when defaultValue is provided', async () => {
+		const { getByTestId } = render(ComboboxTest, { defaultValue: 'Chocolate' });
+		const input = getByTestId('input');
+
+		expect(input).toHaveValue('Chocolate');
+	});
+
+	test('Options with undefined values can be selected', async () => {
+		const options: ComboboxOptionProps[] = [
+			{ label: '1234', value: { id: 1234, station: undefined, lastTransmission: '2023-01-01' } },
+			{ label: '4321', value: { id: 4321, station: undefined, lastTransmission: '2023-01-01' } },
+			{ label: '2341', value: { id: 2341, station: undefined, lastTransmission: '2023-01-01' } },
+			{ label: '3412', value: { id: 3412, station: undefined, lastTransmission: '2023-01-01' } },
+			{ label: '5656', value: { id: 5656, station: 'Station 1', lastTransmission: '2023-01-01' } },
+		];
+
+		const { getByTestId } = render(ComboboxTest, { options });
+		const input = getByTestId('input');
+		const menu = getByTestId('menu');
+		const user = userEvent.setup();
+
+		expect(input).not.toHaveValue(options[0].label);
+
+		expect(menu).not.toBeVisible();
+		await user.click(input);
+		expect(menu).toBeVisible();
+
+		const firstItem = menu.querySelector('[data-melt-combobox-option]');
+		if (!firstItem) throw new Error('No option found');
+
+		await user.click(firstItem);
+
+		expect(menu).not.toBeVisible();
+		expect(input).toHaveValue(options[0].label);
+
+		await user.click(input);
+		expect(menu).toBeVisible();
+		expect(firstItem).toHaveAttribute('data-selected');
+	});
+
+	test.todo('Selects multiple items when `multiple` is true');
+	test.todo('Manually setting the value updates the label');
+	test.todo('Updating options and setting the value updates the label');
+	test.todo('Respects the `closeOnEscape` prop');
+	test.todo('Respects the `closeOnOutsideClick` prop');
+	test.todo('Disabled combobox cannot be opened');
+	test.todo('Options loop when loop prop is set');
+});
diff --git a/src/tests/combobox/ComboboxTest.svelte b/src/tests/combobox/ComboboxTest.svelte
new file mode 100644
index 00000000..b9dc1caa
--- /dev/null
+++ b/src/tests/combobox/ComboboxTest.svelte
@@ -0,0 +1,53 @@
+<script lang="ts">
+	import { createCombobox, melt, type ComboboxOptionProps } from '$lib/index.js';
+
+	export let options: ComboboxOptionProps[] = [
+		{ label: '1234', value: { id: 1234, station: undefined, lastTransmission: '2023-01-01' } },
+		{ label: '4321', value: { id: 4321, station: undefined, lastTransmission: '2023-01-01' } },
+		{ label: '2341', value: { id: 2341, station: undefined, lastTransmission: '2023-01-01' } },
+		{ label: '3412', value: { id: 3412, station: undefined, lastTransmission: '2023-01-01' } },
+		{ label: '5656', value: { id: 5656, station: 'Station 1', lastTransmission: '2023-01-01' } },
+	];
+	export let multiple = false;
+	export let defaultValue: string | undefined = undefined;
+
+	const {
+		elements: { menu, input, option, label },
+		states: { open, inputValue, selected },
+	} = createCombobox({
+		multiple,
+		defaultSelected: defaultValue
+			? {
+					value: defaultValue,
+					label: defaultValue,
+			  }
+			: undefined,
+	});
+
+	$: if (!$open) {
+		$inputValue = $selected?.label || '';
+	}
+</script>
+
+<main>
+	<!-- svelte-ignore a11y-label-has-associated-control - $label contains the 'for' attribute -->
+	<label use:melt={$label} data-testid="label">Label</label>
+
+	<input use:melt={$input} data-testid="input" />
+
+	<ul use:melt={$menu} data-testid="menu">
+		<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
+		<div tabindex="0">
+			{#each options as o, index (index)}
+				<li use:melt={$option(o)}>
+					<div>
+						<span>{o.label}</span>
+						<span>{o.value}</span>
+					</div>
+				</li>
+			{:else}
+				<li>No results found</li>
+			{/each}
+		</div>
+	</ul>
+</main>
diff --git a/src/tests/date-field/DateField.spec.ts b/src/tests/date-field/DateField.spec.ts
index 59229b2d..da38d0db 100644
--- a/src/tests/date-field/DateField.spec.ts
+++ b/src/tests/date-field/DateField.spec.ts
@@ -11,11 +11,21 @@ import {
 	parseAbsoluteToLocal,
 	toZoned,
 } from '@internationalized/date';
+import type { CreateDateFieldProps } from '$lib';
 
 const calendarDateOther = new CalendarDate(1980, 1, 20);
 const calendarDateTimeOther = new CalendarDateTime(1980, 1, 20, 12, 30, 0, 0);
 const zonedDateTimeOther = toZoned(calendarDateTimeOther, 'America/New_York');
 
+function setup(props: CreateDateFieldProps = {}) {
+	const user = userEvent.setup();
+	const returned = render(DateFieldTest, props);
+	return {
+		...returned,
+		user,
+	};
+}
+
 describe('DateField', () => {
 	describe('Accessibility', () => {
 		test('has no accessibility violations', async () => {
@@ -26,7 +36,7 @@ describe('DateField', () => {
 	});
 
 	test('segments populated with defaultValue - CalendarDate', async () => {
-		const { getByTestId } = render(DateFieldTest, {
+		const { getByTestId } = setup({
 			defaultValue: calendarDateOther,
 		});
 
@@ -40,8 +50,9 @@ describe('DateField', () => {
 		expect(yearSegment).toHaveTextContent(String(calendarDateOther.year));
 		expect(insideValue).toHaveTextContent(calendarDateOther.toString());
 	});
+
 	test('segments populated with defaultValue - CalendarDateTime', async () => {
-		const { getByTestId } = render(DateFieldTest, {
+		const { getByTestId } = setup({
 			defaultValue: calendarDateTimeOther,
 		});
 
@@ -61,7 +72,7 @@ describe('DateField', () => {
 	});
 
 	test('segments populated with defaultValue - ZonedDateTime', async () => {
-		const { getByTestId } = render(DateFieldTest, {
+		const { getByTestId } = setup({
 			defaultValue: zonedDateTimeOther,
 		});
 
@@ -85,7 +96,7 @@ describe('DateField', () => {
 	});
 
 	test('locale changes segment positioning', async () => {
-		const { getByTestId } = render(DateFieldTest, {
+		const { getByTestId } = setup({
 			locale: 'en-UK',
 		});
 
@@ -101,7 +112,7 @@ describe('DateField', () => {
 	});
 
 	test('certain locales do not show day period segment', async () => {
-		const { queryByTestId } = render(DateFieldTest, {
+		const { queryByTestId } = setup({
 			locale: 'en-UK',
 			defaultValue: calendarDateTimeOther,
 		});
@@ -109,14 +120,13 @@ describe('DateField', () => {
 	});
 
 	test('certain locales do show day period segment', async () => {
-		const { queryByTestId } = render(DateFieldTest, {
+		const { queryByTestId } = setup({
 			defaultValue: calendarDateTimeOther,
 		});
 		expect(queryByTestId('dayPeriod')).not.toBeNull();
 	});
 	test('focuses first segment on click', async () => {
-		const user = userEvent.setup();
-		const { getByTestId } = render(DateFieldTest);
+		const { getByTestId, user } = setup();
 
 		const firstSegment = getByTestId('month');
 		await user.click(firstSegment);
@@ -125,8 +135,7 @@ describe('DateField', () => {
 	});
 
 	test('increments segment on arrow up', async () => {
-		const user = userEvent.setup();
-		const { getByTestId } = render(DateFieldTest, {
+		const { getByTestId, user } = setup({
 			defaultPlaceholder: calendarDateOther,
 		});
 		const firstSegment = getByTestId('month');
@@ -142,8 +151,7 @@ describe('DateField', () => {
 	});
 
 	test('increments segment on arrow down', async () => {
-		const user = userEvent.setup();
-		const { getByTestId } = render(DateFieldTest, {
+		const { getByTestId, user } = setup({
 			defaultPlaceholder: calendarDateOther,
 		});
 
@@ -160,8 +168,7 @@ describe('DateField', () => {
 	});
 
 	test('increments segment on arrow down', async () => {
-		const user = userEvent.setup();
-		const { getByTestId } = render(DateFieldTest, {
+		const { getByTestId, user } = setup({
 			defaultPlaceholder: calendarDateOther,
 		});
 
@@ -178,8 +185,7 @@ describe('DateField', () => {
 	});
 
 	test('navigates segments using arrow keys', async () => {
-		const user = userEvent.setup();
-		const { getByTestId } = render(DateFieldTest);
+		const { getByTestId, user } = setup();
 
 		const monthSegment = getByTestId('month');
 		const daySegment = getByTestId('day');
@@ -200,8 +206,7 @@ describe('DateField', () => {
 	});
 
 	test('navigates segments using tab', async () => {
-		const user = userEvent.setup();
-		const { getByTestId } = render(DateFieldTest);
+		const { getByTestId, user } = setup();
 
 		const monthSegment = getByTestId('month');
 		const daySegment = getByTestId('day');
@@ -216,8 +221,7 @@ describe('DateField', () => {
 	});
 
 	test('disabled prop prevents interaction', async () => {
-		const user = userEvent.setup();
-		const { getByTestId } = render(DateFieldTest, {
+		const { getByTestId, user } = setup({
 			disabled: true,
 		});
 		const monthSegment = getByTestId('month');
@@ -238,8 +242,7 @@ describe('DateField', () => {
 	});
 
 	test('readonly prop prevents modifying segments', async () => {
-		const user = userEvent.setup();
-		const { getByTestId } = render(DateFieldTest, {
+		const { getByTestId, user } = setup({
 			readonly: true,
 			defaultValue: calendarDateOther,
 		});
@@ -256,8 +259,7 @@ describe('DateField', () => {
 	});
 
 	test('if selected date unavailable, mark field as invalid', async () => {
-		const user = userEvent.setup();
-		const { getByTestId } = render(DateFieldTest, {
+		const { getByTestId, user } = setup({
 			granularity: 'day',
 			isDateUnavailable: (date) => {
 				return date.day === 20;
@@ -288,8 +290,7 @@ describe('DateField', () => {
 	});
 
 	test('hourcycle prop changes the hour cycle', async () => {
-		const user = userEvent.setup();
-		const { getByTestId, queryByTestId } = render(DateFieldTest, {
+		const { getByTestId, queryByTestId, user } = setup({
 			defaultValue: calendarDateTimeOther,
 			hourCycle: 24,
 		});
@@ -305,7 +306,7 @@ describe('DateField', () => {
 	});
 
 	test('day granularity overrides default displayed segments', async () => {
-		const { getByTestId, queryByTestId } = render(DateFieldTest, {
+		const { getByTestId, queryByTestId } = setup({
 			defaultValue: calendarDateTimeOther,
 			granularity: 'day',
 		});
@@ -326,7 +327,7 @@ describe('DateField', () => {
 	});
 
 	test('minute granularity overrides default displayed segments', async () => {
-		const { queryByTestId } = render(DateFieldTest, {
+		const { queryByTestId } = setup({
 			defaultValue: calendarDateOther,
 			granularity: 'minute',
 		});
@@ -344,8 +345,7 @@ describe('DateField', () => {
 	});
 
 	test('changing the dayperiod segment changes the value', async () => {
-		const user = userEvent.setup();
-		const { getByTestId } = render(DateFieldTest, {
+		const { getByTestId, user } = setup({
 			defaultValue: calendarDateTimeOther,
 		});
 
@@ -362,8 +362,7 @@ describe('DateField', () => {
 	});
 
 	test('spamming 3 takes you all the way through the segment', async () => {
-		const user = userEvent.setup();
-		const { getByTestId } = render(DateFieldTest, {
+		const { getByTestId, user } = setup({
 			defaultValue: calendarDateTimeOther,
 			granularity: 'minute',
 		});
@@ -399,8 +398,7 @@ describe('DateField', () => {
 	});
 
 	test('fully overwrite on first click and type - month', async () => {
-		const user = userEvent.setup();
-		const { getByTestId } = render(DateFieldTest, {
+		const { getByTestId, user } = setup({
 			defaultValue: calendarDateTimeOther,
 			granularity: 'second',
 		});
@@ -414,8 +412,7 @@ describe('DateField', () => {
 	});
 
 	test('fully overwrite on first click and type - day', async () => {
-		const user = userEvent.setup();
-		const { getByTestId } = render(DateFieldTest, {
+		const { getByTestId, user } = setup({
 			defaultValue: calendarDateTimeOther,
 			granularity: 'second',
 		});
@@ -429,8 +426,7 @@ describe('DateField', () => {
 	});
 
 	test('fully overwrite on first click and type - year', async () => {
-		const user = userEvent.setup();
-		const { getByTestId } = render(DateFieldTest, {
+		const { getByTestId, user } = setup({
 			defaultValue: calendarDateTimeOther,
 			granularity: 'second',
 		});
@@ -444,8 +440,7 @@ describe('DateField', () => {
 	});
 
 	test('fully overwrite on first click and type - hour', async () => {
-		const user = userEvent.setup();
-		const { getByTestId } = render(DateFieldTest, {
+		const { getByTestId, user } = setup({
 			defaultValue: calendarDateTimeOther,
 			granularity: 'second',
 		});
@@ -460,7 +455,7 @@ describe('DateField', () => {
 
 	test('fully overwrite on first click and type - minute', async () => {
 		const user = userEvent.setup();
-		const { getByTestId } = render(DateFieldTest, {
+		const { getByTestId } = setup({
 			defaultValue: calendarDateTimeOther,
 			granularity: 'second',
 		});
@@ -474,7 +469,7 @@ describe('DateField', () => {
 	});
 
 	test('displays correct timezone with ZonedDateTime value - now', async () => {
-		const { getByTestId } = render(DateFieldTest, {
+		const { getByTestId } = setup({
 			defaultValue: now('America/Los_Angeles'),
 		});
 
@@ -487,7 +482,7 @@ describe('DateField', () => {
 	});
 
 	test('displays correct timezone with ZonedDateTime value - absolute to local', async () => {
-		const { getByTestId } = render(DateFieldTest, {
+		const { getByTestId } = setup({
 			defaultValue: parseAbsoluteToLocal('2023-10-12T12:30:00Z'),
 		});
 
@@ -495,6 +490,14 @@ describe('DateField', () => {
 
 		expect(timeZoneSegment).toHaveTextContent(thisTimeZone('2023-10-12T12:30:00Z'));
 	});
+
+	test('clicking the label focuses the first segment', async () => {
+		const { getByTestId, user } = setup();
+		const label = getByTestId('label');
+		const monthSegment = getByTestId('month');
+		await user.click(label);
+		expect(monthSegment).toHaveFocus();
+	});
 });
 
 function isDaylightSavingsTime(): boolean {
diff --git a/src/tests/date-picker/DatePicker.spec.ts b/src/tests/date-picker/DatePicker.spec.ts
index 716cef6d..29530050 100644
--- a/src/tests/date-picker/DatePicker.spec.ts
+++ b/src/tests/date-picker/DatePicker.spec.ts
@@ -7,24 +7,35 @@ import DatePickerTest from './DatePickerTest.svelte';
 import { CalendarDate, CalendarDateTime, toZoned, today } from '@internationalized/date';
 import { tick } from 'svelte';
 import { sleep } from '$lib/internal/helpers';
+import type { CreateDatePickerProps } from '$lib';
 
 const calendarDateToday = today('America/New_York');
 const calendarDate = new CalendarDate(1980, 1, 20);
 const calendarDateTime = new CalendarDateTime(1980, 1, 20, 12, 30, 0, 0);
 const zonedDateTime = toZoned(calendarDateTime, 'America/New_York');
 
+function setup(props: CreateDatePickerProps = {}) {
+	const user = userEvent.setup();
+	const returned = render(DatePickerTest, props);
+	const trigger = returned.getByTestId('trigger');
+	return {
+		...returned,
+		user,
+		trigger,
+	};
+}
+
 describe('DatePicker', () => {
 	describe('Accessibility', () => {
 		test('has no accessibility violations', async () => {
-			const { container } = render(DatePickerTest);
+			const { container } = setup();
 
 			expect(await axe(container)).toHaveNoViolations();
 		});
 	});
 	describe('Props', () => {
 		test('populated with defaultValue - CalendarDate', async () => {
-			const user = userEvent.setup();
-			const { getByTestId, container } = render(DatePickerTest, {
+			const { getByTestId, user, trigger } = setup({
 				defaultValue: calendarDate,
 			});
 
@@ -38,21 +49,19 @@ describe('DatePicker', () => {
 			expect(yearSegment).toHaveTextContent(String(calendarDate.year));
 			expect(insideValue).toHaveTextContent(calendarDate.toString());
 
-			const trigger = getByTestId('trigger');
 			await user.click(trigger);
 
 			const calendar = getByTestId('calendar');
 			expect(calendar).toBeVisible();
 
-			const selectedDay = container.querySelector('[data-selected]');
+			const selectedDay = calendar.querySelector('[data-selected]');
 			expect(selectedDay).toHaveTextContent(String(calendarDate.day));
 
 			const heading = getByTestId('heading');
 			expect(heading).toHaveTextContent('January 1980');
 		});
 		test('populated with defaultValue - CalendarDateTime', async () => {
-			const user = userEvent.setup();
-			const { getByTestId, container } = render(DatePickerTest, {
+			const { getByTestId, user, trigger } = setup({
 				defaultValue: calendarDateTime,
 			});
 
@@ -70,13 +79,12 @@ describe('DatePicker', () => {
 			expect(minuteSegment).toHaveTextContent(String(calendarDateTime.minute));
 			expect(insideValue).toHaveTextContent(calendarDateTime.toString());
 
-			const trigger = getByTestId('trigger');
 			await user.click(trigger);
 
 			const calendar = getByTestId('calendar');
 			expect(calendar).toBeVisible();
 
-			const selectedDay = container.querySelector('[data-selected]');
+			const selectedDay = calendar.querySelector('[data-selected]');
 			expect(selectedDay).toHaveTextContent(String(calendarDateTime.day));
 
 			const heading = getByTestId('heading');
@@ -84,8 +92,7 @@ describe('DatePicker', () => {
 		});
 
 		test('populated with defaultValue - ZonedDateTime', async () => {
-			const user = userEvent.setup();
-			const { getByTestId, container } = render(DatePickerTest, {
+			const { getByTestId, trigger, user } = setup({
 				defaultValue: zonedDateTime,
 			});
 
@@ -107,13 +114,12 @@ describe('DatePicker', () => {
 			expect(timeZoneSegment).toHaveTextContent(String('EST'));
 			expect(insideValue).toHaveTextContent(zonedDateTime.toString());
 
-			const trigger = getByTestId('trigger');
 			await user.click(trigger);
 
 			const calendar = getByTestId('calendar');
 			expect(calendar).toBeVisible();
 
-			const selectedDay = container.querySelector('[data-selected]');
+			const selectedDay = calendar.querySelector('[data-selected]');
 			expect(selectedDay).toHaveTextContent(String(zonedDateTime.day));
 
 			const heading = getByTestId('heading');
@@ -121,12 +127,10 @@ describe('DatePicker', () => {
 		});
 
 		test('month navigation', async () => {
-			const user = userEvent.setup();
-			const { getByTestId } = render(DatePickerTest, {
+			const { getByTestId, user, trigger } = setup({
 				defaultValue: zonedDateTime,
 			});
 
-			const trigger = getByTestId('trigger');
 			await user.click(trigger);
 
 			const calendar = getByTestId('calendar');
@@ -149,33 +153,29 @@ describe('DatePicker', () => {
 		});
 
 		test('prevent deselection', async () => {
-			const user = userEvent.setup();
-			const { getByTestId, container } = render(DatePickerTest, {
+			const { getByTestId, user, trigger } = setup({
 				defaultValue: zonedDateTime,
 				preventDeselect: true,
 			});
 
-			const trigger = getByTestId('trigger');
 			await user.click(trigger);
 
 			const calendar = getByTestId('calendar');
 			expect(calendar).toBeVisible();
 
-			const selectedDay = container.querySelector('[data-selected]') as HTMLElement;
+			const selectedDay = calendar.querySelector('[data-selected]') as HTMLElement;
 			expect(selectedDay).toHaveTextContent(String(zonedDateTime.day));
 
 			await user.click(selectedDay);
 
-			const selectedDayAfterClick = container.querySelector('[data-selected]') as HTMLElement;
+			const selectedDayAfterClick = calendar.querySelector('[data-selected]') as HTMLElement;
 			expect(selectedDayAfterClick).toHaveTextContent(String(zonedDateTime.day));
 		});
 
 		test('selection with mouse', async () => {
-			const user = userEvent.setup();
-			const { getByTestId } = render(DatePickerTest, {
+			const { getByTestId, user, trigger } = setup({
 				defaultPlaceholder: zonedDateTime,
 			});
-			const trigger = getByTestId('trigger');
 			await user.click(trigger);
 			const calendar = getByTestId('calendar');
 			expect(calendar).toBeVisible();
@@ -189,11 +189,9 @@ describe('DatePicker', () => {
 		});
 
 		test('selection with keyboard', async () => {
-			const user = userEvent.setup();
-			const { getByTestId } = render(DatePickerTest, {
+			const { getByTestId, trigger, user } = setup({
 				defaultPlaceholder: zonedDateTime,
 			});
-			const trigger = getByTestId('trigger');
 			await user.click(trigger);
 			await sleep(1);
 			const calendar = getByTestId('calendar');
@@ -218,7 +216,7 @@ describe('DatePicker', () => {
 		});
 
 		test('locale changes segment positioning', async () => {
-			const { getByTestId } = render(DatePickerTest, {
+			const { getByTestId } = setup({
 				locale: 'en-UK',
 			});
 
@@ -234,7 +232,7 @@ describe('DatePicker', () => {
 		});
 
 		test('certain locales do not show day period segment', async () => {
-			const { queryByTestId } = render(DatePickerTest, {
+			const { queryByTestId } = setup({
 				locale: 'en-UK',
 				defaultValue: calendarDateTime,
 			});
@@ -242,7 +240,7 @@ describe('DatePicker', () => {
 		});
 
 		test('certain locales do show day period segment', async () => {
-			const { queryByTestId } = render(DatePickerTest, {
+			const { queryByTestId } = setup({
 				defaultValue: calendarDateTime,
 			});
 			expect(queryByTestId('dayPeriod')).not.toBeNull();
@@ -251,8 +249,7 @@ describe('DatePicker', () => {
 
 	describe('Navigation', () => {
 		test('focuses first segment on click', async () => {
-			const user = userEvent.setup();
-			const { getByTestId } = render(DatePickerTest);
+			const { getByTestId, user } = setup();
 
 			const firstSegment = getByTestId('month');
 			await user.click(firstSegment);
@@ -261,8 +258,7 @@ describe('DatePicker', () => {
 		});
 
 		test('increments segment on arrow up', async () => {
-			const user = userEvent.setup();
-			const { getByTestId } = render(DatePickerTest, {
+			const { getByTestId, user } = setup({
 				defaultPlaceholder: calendarDateToday,
 			});
 			const firstSegment = getByTestId('month');
@@ -279,7 +275,7 @@ describe('DatePicker', () => {
 
 		test('increments segment on arrow down', async () => {
 			const user = userEvent.setup();
-			const { getByTestId } = render(DatePickerTest, {
+			const { getByTestId } = setup({
 				defaultPlaceholder: calendarDateToday,
 			});
 
@@ -296,8 +292,7 @@ describe('DatePicker', () => {
 		});
 
 		test('increments segment on arrow down', async () => {
-			const user = userEvent.setup();
-			const { getByTestId } = render(DatePickerTest, {
+			const { getByTestId, user } = setup({
 				defaultPlaceholder: calendarDateToday,
 			});
 
@@ -314,8 +309,7 @@ describe('DatePicker', () => {
 		});
 
 		test('navigates segments using arrow keys', async () => {
-			const user = userEvent.setup();
-			const { getByTestId } = render(DatePickerTest);
+			const { getByTestId, user } = setup();
 
 			const monthSegment = getByTestId('month');
 			const daySegment = getByTestId('day');
@@ -343,13 +337,11 @@ describe('DatePicker', () => {
 		});
 
 		test('navigates segments using tab', async () => {
-			const user = userEvent.setup();
-			const { getByTestId } = render(DatePickerTest);
+			const { getByTestId, user, trigger } = setup();
 
 			const monthSegment = getByTestId('month');
 			const daySegment = getByTestId('day');
 			const yearSegment = getByTestId('year');
-			const triggerSegment = getByTestId('trigger');
 
 			await user.click(monthSegment);
 			await user.keyboard(kbd.TAB);
@@ -359,16 +351,14 @@ describe('DatePicker', () => {
 			expect(yearSegment).toHaveFocus();
 
 			await user.keyboard(kbd.TAB);
-			expect(triggerSegment).toHaveFocus();
+			expect(trigger).toHaveFocus();
 		});
 
 		test('when no time selected, selecting', async () => {
-			const user = userEvent.setup();
-			const { getByTestId, queryByTestId } = render(DatePickerTest, {
+			const { getByTestId, queryByTestId, user, trigger } = setup({
 				granularity: 'minute',
 			});
 
-			const trigger = getByTestId('trigger');
 			await user.click(trigger);
 
 			const calendar = queryByTestId('calendar');
@@ -393,7 +383,7 @@ describe('DatePicker', () => {
 		});
 
 		test('correct segments are rendered with placeholder', async () => {
-			const { getByTestId } = render(DatePickerTest, {
+			const { getByTestId } = setup({
 				defaultPlaceholder: new CalendarDateTime(2021, 2, 1),
 			});
 
@@ -404,4 +394,12 @@ describe('DatePicker', () => {
 			}
 		});
 	});
+
+	test('clicking the label focuses the first segment', async () => {
+		const { getByTestId, user } = setup();
+		const label = getByTestId('label');
+		const monthSegment = getByTestId('month');
+		await user.click(label);
+		expect(monthSegment).toHaveFocus();
+	});
 });
diff --git a/src/tests/date-range-field/DateRangeField.spec.ts b/src/tests/date-range-field/DateRangeField.spec.ts
index a06d5d34..6899d8b8 100644
--- a/src/tests/date-range-field/DateRangeField.spec.ts
+++ b/src/tests/date-range-field/DateRangeField.spec.ts
@@ -5,6 +5,7 @@ import { axe } from 'jest-axe';
 import { describe } from 'vitest';
 import DateRangeFieldTest from './DateRangeFieldTest.svelte';
 import { CalendarDate, CalendarDateTime, toZoned } from '@internationalized/date';
+import type { CreateDateRangeFieldProps } from '$lib';
 
 const exampleDate = {
 	start: new CalendarDate(2022, 1, 1),
@@ -21,6 +22,15 @@ const exampleZonedDateTime = {
 	end: toZoned(exampleDateTime.end, 'America/New_York'),
 };
 
+function setup(props: CreateDateRangeFieldProps = {}) {
+	const user = userEvent.setup();
+	const returned = render(DateRangeFieldTest, props);
+	return {
+		...returned,
+		user,
+	};
+}
+
 describe('DateField', () => {
 	describe('Accessibility', () => {
 		test('has no accessibility violations', async () => {
@@ -31,7 +41,7 @@ describe('DateField', () => {
 	});
 
 	test('segments populated with defaultValue - CalendarDate', async () => {
-		const { getByTestId } = render(DateRangeFieldTest, {
+		const { getByTestId } = setup({
 			defaultValue: exampleDate,
 		});
 
@@ -46,7 +56,7 @@ describe('DateField', () => {
 		});
 	});
 	test('segments populated with defaultValue - CalendarDateTime', async () => {
-		const { getByTestId } = render(DateRangeFieldTest, {
+		const { getByTestId } = setup({
 			defaultValue: exampleDateTime,
 		});
 
@@ -64,7 +74,7 @@ describe('DateField', () => {
 	});
 
 	test('segments populated with defaultValue - ZonedDateTime', async () => {
-		const { getByTestId } = render(DateRangeFieldTest, {
+		const { getByTestId } = setup({
 			defaultValue: exampleZonedDateTime,
 		});
 
@@ -81,15 +91,14 @@ describe('DateField', () => {
 	});
 
 	test('navigation between fields - left to right', async () => {
-		const user = userEvent.setup();
-		const { getByTestId } = render(DateRangeFieldTest, {
+		const { getByTestId, user } = setup({
 			defaultValue: exampleDate,
 		});
 
 		const fields = ['start', 'end'] as const;
 		const segments = ['month', 'day', 'year'] as const;
 
-		await userEvent.click(getByTestId('start-month'));
+		await user.click(getByTestId('start-month'));
 
 		for (const field of fields) {
 			for (const segment of segments) {
@@ -100,7 +109,7 @@ describe('DateField', () => {
 			}
 		}
 
-		await userEvent.click(getByTestId('start-month'));
+		await user.click(getByTestId('start-month'));
 
 		for (const field of fields) {
 			for (const segment of segments) {
@@ -112,15 +121,14 @@ describe('DateField', () => {
 		}
 	});
 	test('navigation between fields - right to left', async () => {
-		const user = userEvent.setup();
-		const { getByTestId } = render(DateRangeFieldTest, {
+		const { getByTestId, user } = setup({
 			defaultValue: exampleDate,
 		});
 
 		const fields = ['end', 'start'] as const;
 		const segments = ['year', 'day', 'month'] as const;
 
-		await userEvent.click(getByTestId('end-year'));
+		await user.click(getByTestId('end-year'));
 
 		for (const field of fields) {
 			for (const segment of segments) {
@@ -131,7 +139,7 @@ describe('DateField', () => {
 			}
 		}
 
-		await userEvent.click(getByTestId('end-year'));
+		await user.click(getByTestId('end-year'));
 
 		for (const field of fields) {
 			for (const segment of segments) {
@@ -142,4 +150,12 @@ describe('DateField', () => {
 			}
 		}
 	});
+
+	test('clicking the label focuses the first segment', async () => {
+		const { getByTestId, user } = setup();
+		const label = getByTestId('label');
+		const monthSegment = getByTestId('start-month');
+		await user.click(label);
+		expect(monthSegment).toHaveFocus();
+	});
 });
diff --git a/src/tests/range-calendar/RangeCalendar.spec.ts b/src/tests/range-calendar/RangeCalendar.spec.ts
index dcacb524..76e59024 100644
--- a/src/tests/range-calendar/RangeCalendar.spec.ts
+++ b/src/tests/range-calendar/RangeCalendar.spec.ts
@@ -7,7 +7,7 @@ import RangeCalendarTest from './RangeCalendarTest.svelte';
 import { CalendarDate, CalendarDateTime, toZoned, type DateValue } from '@internationalized/date';
 import { writable } from 'svelte/store';
 import { tick } from 'svelte';
-import type { DateRange } from '$lib';
+import type { CreateRangeCalendarProps, DateRange } from '$lib';
 
 const calendarDateRange = {
 	start: new CalendarDate(1980, 1, 20),
@@ -28,6 +28,18 @@ const controlledCalendarDateRange = writable<DateRange>(calendarDateRange);
 const controlledCalendarDateTimeRange = writable<DateRange>(calendarDateTimeRange);
 const controlledZonedDateTimeRange = writable<DateRange>(zonedDateTimeRange);
 
+function setup(props: CreateRangeCalendarProps = {}) {
+	const user = userEvent.setup();
+	const returned = render(RangeCalendarTest, props);
+	const calendar = returned.getByTestId('calendar');
+	expect(calendar).toBeVisible();
+	return {
+		...returned,
+		user,
+		calendar,
+	};
+}
+
 describe('Range Calendar', () => {
 	describe('Accessibility', () => {
 		test('has no accessibility violations', async () => {
@@ -37,28 +49,22 @@ describe('Range Calendar', () => {
 		});
 	});
 	test('populated with defaultValue - CalendarDate', async () => {
-		const { getByTestId, container } = render(RangeCalendarTest, {
+		const { getByTestId, calendar } = setup({
 			defaultValue: calendarDateRange,
 		});
 
-		const calendar = getByTestId('calendar');
-		expect(calendar).toBeVisible();
-
-		const selectedDays = container.querySelectorAll('[data-selected]');
+		const selectedDays = calendar.querySelectorAll('[data-selected]');
 		expect(selectedDays).toHaveLength(6);
 
 		const heading = getByTestId('heading');
 		expect(heading).toHaveTextContent('January 1980');
 	});
 	test('populated with defaultValue - CalendarDateTime', async () => {
-		const { getByTestId, container } = render(RangeCalendarTest, {
+		const { getByTestId, calendar } = setup({
 			defaultValue: calendarDateTimeRange,
 		});
 
-		const calendar = getByTestId('calendar');
-		expect(calendar).toBeVisible();
-
-		const selectedDays = container.querySelectorAll('[data-selected]');
+		const selectedDays = calendar.querySelectorAll('[data-selected]');
 		expect(selectedDays).toHaveLength(6);
 
 		const heading = getByTestId('heading');
@@ -66,14 +72,11 @@ describe('Range Calendar', () => {
 	});
 
 	test('populated with defaultValue - ZonedDateTime', async () => {
-		const { getByTestId, container } = render(RangeCalendarTest, {
+		const { getByTestId, calendar } = setup({
 			defaultValue: zonedDateTimeRange,
 		});
 
-		const calendar = getByTestId('calendar');
-		expect(calendar).toBeVisible();
-
-		const selectedDays = container.querySelectorAll('[data-selected]');
+		const selectedDays = calendar.querySelectorAll('[data-selected]');
 		expect(selectedDays).toHaveLength(6);
 
 		const heading = getByTestId('heading');
@@ -81,42 +84,35 @@ describe('Range Calendar', () => {
 	});
 
 	test('populated with controlled value - CalendarDate', async () => {
-		const { getByTestId, container } = render(RangeCalendarTest, {
+		const { getByTestId, calendar } = setup({
 			value: controlledCalendarDateRange,
 		});
 
-		const calendar = getByTestId('calendar');
-		expect(calendar).toBeVisible();
-
-		const selectedDays = container.querySelectorAll('[data-selected]');
+		const selectedDays = calendar.querySelectorAll('[data-selected]');
 		expect(selectedDays).toHaveLength(6);
 
 		const heading = getByTestId('heading');
 		expect(heading).toHaveTextContent('January 1980');
 	});
+
 	test('populated with controlled value - CalendarDateTime', async () => {
-		const { getByTestId, container } = render(RangeCalendarTest, {
+		const { getByTestId, calendar } = setup({
 			value: controlledCalendarDateTimeRange,
 		});
 
-		const calendar = getByTestId('calendar');
-		expect(calendar).toBeVisible();
-
-		const selectedDays = container.querySelectorAll('[data-selected]');
+		const selectedDays = calendar.querySelectorAll('[data-selected]');
 		expect(selectedDays).toHaveLength(6);
 
 		const heading = getByTestId('heading');
 		expect(heading).toHaveTextContent('January 1980');
 	});
+
 	test('populated with controlled value - CalendarDateTime', async () => {
-		const { getByTestId, container } = render(RangeCalendarTest, {
+		const { getByTestId, calendar } = setup({
 			value: controlledZonedDateTimeRange,
 		});
 
-		const calendar = getByTestId('calendar');
-		expect(calendar).toBeVisible();
-
-		const selectedDays = container.querySelectorAll('[data-selected]');
+		const selectedDays = calendar.querySelectorAll('[data-selected]');
 		expect(selectedDays).toHaveLength(6);
 
 		const heading = getByTestId('heading');
@@ -124,14 +120,10 @@ describe('Range Calendar', () => {
 	});
 
 	test('month navigation', async () => {
-		const user = userEvent.setup();
-		const { getByTestId } = render(RangeCalendarTest, {
+		const { getByTestId, user } = setup({
 			defaultValue: calendarDateRange,
 		});
 
-		const calendar = getByTestId('calendar');
-		expect(calendar).toBeVisible();
-
 		const heading = getByTestId('heading');
 		expect(heading).toHaveTextContent('January 1980');
 
@@ -149,14 +141,10 @@ describe('Range Calendar', () => {
 	});
 
 	test('selection after range selected resets range', async () => {
-		const user = userEvent.setup();
-		const { getByTestId, container } = render(RangeCalendarTest, {
+		const { getByTestId, calendar, user } = setup({
 			defaultValue: calendarDateRange,
 		});
 
-		const calendar = getByTestId('calendar');
-		expect(calendar).toBeVisible();
-
 		const startValue = getByTestId('start-value');
 		const endValue = getByTestId('end-value');
 
@@ -167,24 +155,21 @@ describe('Range Calendar', () => {
 		await user.click(fifthDayInMonth);
 		expect(fifthDayInMonth).toHaveFocus();
 
-		const selectedDays = container.querySelectorAll('[data-selected]');
+		const selectedDays = calendar.querySelectorAll('[data-selected]');
 		expect(selectedDays).toHaveLength(1);
 		expect(startValue).toHaveTextContent(String(undefined));
 		expect(endValue).toHaveTextContent(String(undefined));
 		const seventhDayInMonth = getByTestId('month-0-date-7');
 		await user.click(seventhDayInMonth);
 		await tick();
-		expect(container.querySelectorAll('[data-selected]')).toHaveLength(3);
+		expect(calendar.querySelectorAll('[data-selected]')).toHaveLength(3);
 	});
 
 	test('selection with keyboard', async () => {
-		const user = userEvent.setup();
-		const { getByTestId } = render(RangeCalendarTest, {
+		const { getByTestId, user, calendar } = setup({
 			defaultPlaceholder: calendarDateRange.start,
 		});
 
-		const calendar = getByTestId('calendar');
-		expect(calendar).toBeVisible();
 		const secondDayInMonth = getByTestId('month-0-date-2');
 		const thirdDayInMonth = getByTestId('month-0-date-3');
 		const fourthDayInMonth = getByTestId('month-0-date-4');
@@ -208,15 +193,11 @@ describe('Range Calendar', () => {
 	});
 
 	test('should display multiple months with numberOfMonths prop', async () => {
-		const user = userEvent.setup();
-		const { getByTestId } = render(RangeCalendarTest, {
+		const { getByTestId, user } = setup({
 			defaultValue: calendarDateRange,
 			numberOfMonths: 2,
 		});
 
-		const calendar = getByTestId('calendar');
-		expect(calendar).toBeVisible();
-
 		const heading = getByTestId('heading');
 		expect(heading).toHaveTextContent('January - February 1980');
 
@@ -240,16 +221,12 @@ describe('Range Calendar', () => {
 	});
 
 	test('multiple months (paged navigation)', async () => {
-		const user = userEvent.setup();
-		const { getByTestId } = render(RangeCalendarTest, {
+		const { getByTestId, user } = setup({
 			defaultValue: calendarDateRange,
 			numberOfMonths: 2,
 			pagedNavigation: true,
 		});
 
-		const calendar = getByTestId('calendar');
-		expect(calendar).toBeVisible();
-
 		const heading = getByTestId('heading');
 		expect(heading).toHaveTextContent('January - February 1980');
 
@@ -279,7 +256,7 @@ describe('Range Calendar', () => {
 	});
 
 	test('fixedWeeks always renders 6 weeks', async () => {
-		const { getByTestId, queryByTestId } = render(RangeCalendarTest, {
+		const { getByTestId, queryByTestId, user } = setup({
 			value: controlledCalendarDateRange,
 			fixedWeeks: true,
 		});
@@ -288,19 +265,19 @@ describe('Range Calendar', () => {
 		const prevButton = getByTestId('prev-button');
 
 		for (let i = 0; i < 12; i++) {
-			await userEvent.click(nextButton);
+			await user.click(nextButton);
 			expect(queryByTestId('week-6')).not.toBeNull();
 		}
 
 		for (let i = 0; i < 12; i++) {
-			await userEvent.click(prevButton);
+			await user.click(prevButton);
 			expect(queryByTestId('week-6')).not.toBeNull();
 		}
 	});
 	test('controlled value should update selected value', async () => {
 		const valueStore = writable<DateRange>(undefined);
 
-		const { getByTestId } = render(RangeCalendarTest, {
+		const { getByTestId } = setup({
 			value: valueStore,
 		});
 
@@ -325,7 +302,7 @@ describe('Range Calendar', () => {
 
 	test('controlled placeholder should change view', async () => {
 		const placeholderStore = writable<DateValue>(calendarDateRange.start);
-		const { getByTestId } = render(RangeCalendarTest, {
+		const { getByTestId } = setup({
 			defaultValue: calendarDateRange,
 			placeholder: placeholderStore,
 		});
@@ -347,48 +324,48 @@ describe('Range Calendar', () => {
 	});
 
 	test('calendar does not navigate before minValue', async () => {
-		const { getByTestId } = render(RangeCalendarTest, {
+		const { getByTestId, user } = setup({
 			defaultValue: calendarDateRange,
 			minValue: new CalendarDate(1979, 11, 25),
 		});
 
 		const prevButton = getByTestId('prev-button');
-		await userEvent.click(prevButton);
+		await user.click(prevButton);
 		const heading = getByTestId('heading');
 		expect(heading).toHaveTextContent('December 1979');
 		expect(prevButton).not.toBeDisabled();
 		expect(prevButton).not.toHaveAttribute('aria-disabled', 'true');
-		await userEvent.click(prevButton);
+		await user.click(prevButton);
 		expect(heading).toHaveTextContent('November 1979');
 
 		expect(prevButton).toBeDisabled();
 		expect(prevButton).toHaveAttribute('aria-disabled', 'true');
 
-		await userEvent.click(prevButton);
+		await user.click(prevButton);
 		expect(heading).toHaveTextContent('November 1979');
 	});
 
 	test('calendar does not navigate after maxValue', async () => {
-		const { getByTestId } = render(RangeCalendarTest, {
+		const { getByTestId, user } = setup({
 			defaultValue: calendarDateRange,
 			maxValue: new CalendarDate(1980, 4, 1),
 		});
 
 		const nextButton = getByTestId('next-button');
-		await userEvent.click(nextButton);
+		await user.click(nextButton);
 		const heading = getByTestId('heading');
 		expect(heading).toHaveTextContent('February 1980');
-		await userEvent.click(nextButton);
+		await user.click(nextButton);
 		expect(heading).toHaveTextContent('March 1980');
 		expect(nextButton).not.toBeDisabled();
 		expect(nextButton).not.toHaveAttribute('aria-disabled', 'true');
-		await userEvent.click(nextButton);
+		await user.click(nextButton);
 		expect(heading).toHaveTextContent('April 1980');
 
 		expect(nextButton).toBeDisabled();
 		expect(nextButton).toHaveAttribute('aria-disabled', 'true');
 
-		await userEvent.click(nextButton);
+		await user.click(nextButton);
 		expect(heading).toHaveTextContent('April 1980');
 	});
 
@@ -398,29 +375,29 @@ describe('Range Calendar', () => {
 			end: new CalendarDate(1980, 2, 27),
 		};
 
-		const { getByTestId, container } = render(RangeCalendarTest, {
+		const { getByTestId, calendar, user } = setup({
 			defaultValue: calendarDateRange,
 			onValueChange: () => {
 				return overrideDay;
 			},
 		});
 
-		const selectedDays = container.querySelectorAll('[data-selected]');
+		const selectedDays = calendar.querySelectorAll('[data-selected]');
 		expect(selectedDays).toHaveLength(6);
 
 		const thirdDayInMonth = getByTestId('month-0-date-3');
-		await userEvent.click(thirdDayInMonth);
+		await user.click(thirdDayInMonth);
 		await tick();
 		const fourthDayInMonth = getByTestId('month-0-date-4');
-		await userEvent.click(fourthDayInMonth);
+		await user.click(fourthDayInMonth);
 		await tick();
 
-		const selectedDaysAfterClick = container.querySelectorAll('[data-selected]');
+		const selectedDaysAfterClick = calendar.querySelectorAll('[data-selected]');
 		expect(selectedDaysAfterClick).toHaveLength(3);
 	});
 
 	test('unavailable dates behavior', async () => {
-		const { getByTestId } = render(RangeCalendarTest, {
+		const { getByTestId, user } = setup({
 			defaultPlaceholder: calendarDateRange.start,
 			isDateUnavailable: (date) => {
 				return date.day === 3;
@@ -430,12 +407,12 @@ describe('Range Calendar', () => {
 		const thirdDayInMonth = getByTestId('month-0-date-3');
 		expect(thirdDayInMonth).toHaveAttribute('data-unavailable');
 		expect(thirdDayInMonth).toHaveAttribute('aria-disabled', 'true');
-		await userEvent.click(thirdDayInMonth);
+		await user.click(thirdDayInMonth);
 		expect(thirdDayInMonth).not.toHaveAttribute('data-selected');
 	});
 
 	test('disabled dates behavior', async () => {
-		const { getByTestId } = render(RangeCalendarTest, {
+		const { getByTestId, user } = setup({
 			defaultPlaceholder: calendarDateRange.start,
 			isDateDisabled: (date) => {
 				return date.day === 3;
@@ -445,13 +422,12 @@ describe('Range Calendar', () => {
 		const thirdDayInMonth = getByTestId('month-0-date-3');
 		expect(thirdDayInMonth).toHaveAttribute('data-disabled');
 		expect(thirdDayInMonth).toHaveAttribute('aria-disabled', 'true');
-		await userEvent.click(thirdDayInMonth);
+		await user.click(thirdDayInMonth);
 		expect(thirdDayInMonth).not.toHaveAttribute('data-selected');
 	});
 
 	test('Selection through disabled with double click doesnt select dates', async () => {
-		const user = userEvent.setup();
-		const { getByTestId, container } = render(RangeCalendarTest, {
+		const { getByTestId, container, user } = setup({
 			defaultPlaceholder: calendarDateRange.start,
 			isDateDisabled: (date) => {
 				return date.day === 3;