Date Range Field

Enables users to input a range of dates within a designated field.

Hotel dates
	<script lang="ts">
  import { DateRangeField } from "bits-ui";
</script>
 
<DateRangeField.Root class="group flex w-full max-w-[320px] flex-col gap-1.5">
  <DateRangeField.Label class="block text-sm font-medium select-none">
    Hotel dates
  </DateRangeField.Label>
  <div
    class="flex h-input w-full items-center rounded-input border border-border-input bg-background px-2 py-3 text-sm tracking-[0.01em] text-foreground select-none group-data-invalid:border-destructive focus-within:border-border-input-hover focus-within:shadow-date-field-focus hover:border-border-input-hover"
  >
    {#each ["start", "end"] as const as type (type)}
      <DateRangeField.Input {type}>
        {#snippet children({ segments })}
          {#each segments as { part, value }, i (part + i)}
            <div class="inline-block select-none">
              {#if part === "literal"}
                <DateRangeField.Segment
                  {part}
                  class="p-1 text-muted-foreground"
                >
                  {value}
                </DateRangeField.Segment>
              {:else}
                <DateRangeField.Segment
                  {part}
                  class="rounded-5px px-1 py-1 hover:bg-muted focus:bg-muted focus:text-foreground focus-visible:ring-0! focus-visible:ring-offset-0! aria-[valuetext=Empty]:text-muted-foreground"
                >
                  {value}
                </DateRangeField.Segment>
              {/if}
            </div>
          {/each}
        {/snippet}
      </DateRangeField.Input>
      {#if type === "start"}
        <div aria-hidden="true" class="px-1 text-muted-foreground">–⁠⁠⁠⁠⁠</div>
      {/if}
    {/each}
  </div>
</DateRangeField.Root>

Overview

The DateRangeField component combines two Date Field components to create a date range field. Check out the Date Field component documentation for information on how to customize this component.

Structure

	<script lang="ts">
  import { DateRangeField } from "#lib";
</script>
 
<DateRangeField.Root>
  <DateRangeField.Label>Check-in date</DateRangeField.Label>
  {#each ["start", "end"] as const as type}
    <DateRangeField.Input {type}>
      {#snippet children({ segments })}
        {#each segments as { part, value }}
          <DateRangeField.Segment {part}>
            {value}
          </DateRangeField.Segment>
        {/each}
      {/snippet}
    </DateRangeField.Input>
  {/each}
</DateRangeField.Root>

Managing Placeholder State

This section covers how to manage the placeholder state of the component.

Two-Way Binding

Use bind:placeholder for simple, automatic state synchronization:

	<script lang="ts">
  import { DateRangeField } from "bits-ui";
  import { CalendarDateTime } from "@internationalized/date";
  let myPlaceholder = $state(new CalendarDateTime(2024, 8, 3, 12, 30));
</script>
 
<DateRangeField.Root bind:placeholder={myPlaceholder}>
  <!-- ... -->
</DateRangeField.Root>

Fully Controlled

Use a Function Binding for complete control over the state's reads and writes.

	<script lang="ts">
  import { DateRangeField } from "bits-ui";
  import { CalendarDateTime } from "@internationalized/date";
  let myPlaceholder = $state(new CalendarDateTime(2024, 8, 3, 12, 30));
 
  function getPlaceholder() {
    return myPlaceholder;
  }
 
  function setPlaceholder(newPlaceholder: CalendarDateTime) {
    myPlaceholder = newPlaceholder;
  }
</script>
 
<DateRangeField.Root bind:placeholder={getPlaceholder, setPlaceholder}>
  <!-- ... -->
</DateRangeField.Root>

Managing Value State

This section covers how to manage the value state of the component.

Two-Way Binding

Use bind:value for simple, automatic state synchronization:

	<script lang="ts">
  import { DateRangeField, type DateRange } from "bits-ui";
  import { CalendarDateTime } from "@internationalized/date";
  let myValue = $state<DateRange>({
    start: new CalendarDateTime(2024, 8, 3, 12, 30),
    end: new CalendarDateTime(2024, 8, 4, 12, 30),
  });
</script>
 
<button
  onclick={() => {
    value = {
      start: value.start.add({ days: 1 }),
      end: value.end.add({ days: 1 }),
    };
  }}
>
  Add 1 day
</button>
<DateRangeField.Root bind:value={myValue}>
  <!-- ... -->
</DateRangeField.Root>

Fully Controlled

Use a Function Binding for complete control over the state's reads and writes.

	<script lang="ts">
  import { DateRangeField } from "bits-ui";
  let myValue = $state<DateRange>({
    start: undefined,
    end: undefined,
  });
 
  function getValue() {
    return myValue;
  }
 
  function setValue(newValue: DateRange) {
    myValue = newValue;
  }
</script>
 
<DateRangeField.Root bind:value={getValue, setValue}>
  <!-- ... -->
</DateRangeField.Root>

API Reference

DateRangeField.Root

The root date field component.

Property Details
value
onValueChange
placeholder
onPlaceholderChange
errorMessageId
validate
onInvalid
minValue
maxValue
granularity
hideTimeZone
hourCycle
locale
disabled
readonly
readonlySegments
required
onStartValueChange
onEndValueChange
ref
children
child
Data Attribute Details
data-date-range-field-root

DateRangeField.Input

The container for the segments of the date field.

Property Details
type
name
ref
children
child
Data Attribute Details
data-invalid
data-disabled
data-date-field-input

DateRangeField.Segment

A segment of the date field.

Property Details
part
ref
children
child
Data Attribute Details
data-invalid
data-disabled
data-segment
data-date-field-segment

DateRangeField.Label

The label for the date field.

Property Details
ref
children
child
Data Attribute Details
data-invalid
data-date-field-label