Date Range Picker

Facilitates the selection of date ranges through an input and calendar-based interface.

llms.txt
Rental Days
	<script lang="ts">
  import { DateRangePicker } from "bits-ui";
  import CalendarBlank from "phosphor-svelte/lib/CalendarBlank";
  import CaretLeft from "phosphor-svelte/lib/CaretLeft";
  import CaretRight from "phosphor-svelte/lib/CaretRight";
</script>
 
<DateRangePicker.Root
  weekdayFormat="short"
  fixedWeeks={true}
  class="flex w-full max-w-[340px] flex-col gap-1.5"
>
  <DateRangePicker.Label class="block select-none text-sm font-medium"
    >Rental Days</DateRangePicker.Label
  >
  <div
    class="h-input rounded-input border-border-input bg-background text-foreground focus-within:border-border-input-hover focus-within:shadow-date-field-focus hover:border-border-input-hover flex w-full select-none items-center border px-2 py-3 text-sm tracking-[0.01em]"
  >
    {#each ["start", "end"] as const as type (type)}
      <DateRangePicker.Input {type}>
        {#snippet children({ segments })}
          {#each segments as { part, value }, i (part + i)}
            <div class="inline-block select-none">
              {#if part === "literal"}
                <DateRangePicker.Segment
                  {part}
                  class="text-muted-foreground p-1"
                >
                  {value}
                </DateRangePicker.Segment>
              {:else}
                <DateRangePicker.Segment
                  {part}
                  class="rounded-5px hover:bg-muted focus:bg-muted focus:text-foreground aria-[valuetext=Empty]:text-muted-foreground focus-visible:ring-0! focus-visible:ring-offset-0! px-1 py-1"
                >
                  {value}
                </DateRangePicker.Segment>
              {/if}
            </div>
          {/each}
        {/snippet}
      </DateRangePicker.Input>
      {#if type === "start"}
        <div aria-hidden="true" class="text-muted-foreground px-1">–⁠⁠⁠⁠⁠</div>
      {/if}
    {/each}
 
    <DateRangePicker.Trigger
      class="text-foreground/60 hover:bg-muted active:bg-dark-10 ml-auto inline-flex size-8 items-center justify-center rounded-[5px] transition-all"
    >
      <CalendarBlank class="size-6" />
    </DateRangePicker.Trigger>
  </div>
  <DateRangePicker.Content sideOffset={6} class="z-50">
    <DateRangePicker.Calendar
      class="rounded-15px border-dark-10 bg-background-alt shadow-popover mt-6 border p-[22px]"
    >
      {#snippet children({ months, weekdays })}
        <DateRangePicker.Header class="flex items-center justify-between">
          <DateRangePicker.PrevButton
            class="rounded-9px bg-background-alt hover:bg-muted inline-flex size-10 items-center justify-center transition-all active:scale-[0.98]"
          >
            <CaretLeft class="size-6" />
          </DateRangePicker.PrevButton>
          <DateRangePicker.Heading class="text-[15px] font-medium" />
          <DateRangePicker.NextButton
            class="rounded-9px bg-background-alt hover:bg-muted inline-flex size-10 items-center justify-center transition-all active:scale-[0.98]"
          >
            <CaretRight class="size-6" />
          </DateRangePicker.NextButton>
        </DateRangePicker.Header>
        <div
          class="flex flex-col space-y-4 pt-4 sm:flex-row sm:space-x-4 sm:space-y-0"
        >
          {#each months as month (month.value)}
            <DateRangePicker.Grid
              class="w-full border-collapse select-none space-y-1"
            >
              <DateRangePicker.GridHead>
                <DateRangePicker.GridRow
                  class="mb-1 flex w-full justify-between"
                >
                  {#each weekdays as day (day)}
                    <DateRangePicker.HeadCell
                      class="text-muted-foreground font-normal! w-10 rounded-md text-xs"
                    >
                      <div>{day.slice(0, 2)}</div>
                    </DateRangePicker.HeadCell>
                  {/each}
                </DateRangePicker.GridRow>
              </DateRangePicker.GridHead>
              <DateRangePicker.GridBody>
                {#each month.weeks as weekDates (weekDates)}
                  <DateRangePicker.GridRow class="flex w-full">
                    {#each weekDates as date (date)}
                      <DateRangePicker.Cell
                        {date}
                        month={month.value}
                        class="p-0! relative m-0 size-10 overflow-visible text-center text-sm focus-within:relative focus-within:z-20"
                      >
                        <DateRangePicker.Day
                          class="rounded-9px text-foreground hover:border-foreground focus-visible:ring-foreground! data-selection-end:rounded-9px data-selection-start:rounded-9px data-highlighted:bg-muted data-selected:bg-muted data-selection-end:bg-foreground data-selection-start:bg-foreground data-disabled:text-foreground/30 data-selected:text-foreground data-selection-end:text-background data-selection-start:text-background data-unavailable:text-muted-foreground data-selected:[&:not([data-selection-start])]:[&:not([data-selection-end])]:focus-visible:border-foreground data-disabled:pointer-events-none data-highlighted:rounded-none  data-outside-month:pointer-events-none data-selected:font-medium data-selection-end:font-medium data-selection-start:font-medium data-selection-start:focus-visible:ring-2 data-selection-start:focus-visible:ring-offset-2! data-unavailable:line-through data-selected:[&:not([data-selection-start])]:[&:not([data-selection-end])]:rounded-none data-selected:[&:not([data-selection-start])]:[&:not([data-selection-end])]:focus-visible:ring-0! data-selected:[&:not([data-selection-start])]:[&:not([data-selection-end])]:focus-visible:ring-offset-0! group relative inline-flex size-10 items-center justify-center overflow-visible whitespace-nowrap border border-transparent bg-transparent p-0 text-sm font-normal transition-all"
                        >
                          <div
                            class="bg-foreground group-data-selected:bg-background group-data-today:block absolute top-[5px] hidden size-1 rounded-full transition-all"
                          ></div>
                          {date.day}
                        </DateRangePicker.Day>
                      </DateRangePicker.Cell>
                    {/each}
                  </DateRangePicker.GridRow>
                {/each}
              </DateRangePicker.GridBody>
            </DateRangePicker.Grid>
          {/each}
        </div>
      {/snippet}
    </DateRangePicker.Calendar>
  </DateRangePicker.Content>
</DateRangePicker.Root>

Structure

	<script lang="ts">
  import { DateRangePicker } from "bits-ui";
</script>
 
<DateRangePicker.Root>
  <DateRangePicker.Label />
  {#each ["start", "end"] as const as type}
    <DateRangePicker.Input {type}>
      {#snippet children({ segments })}
        {#each segments as { part, value }}
          <DateRangePicker.Segment {part}>
            {value}
          </DateRangePicker.Segment>
        {/each}
      {/snippet}
    </DateRangePicker.Input>
  {/each}
  <DateRangePicker.Trigger />
  <DateRangePicker.Content>
    <DateRangePicker.Calendar>
      {#snippet children({ months, weekdays })}
        <DateRangePicker.Header>
          <DateRangePicker.PrevButton />
          <DateRangePicker.Heading />
          <DateRangePicker.NextButton />
        </DateRangePicker.Header>
        {#each months as month}
          <DateRangePicker.Grid>
            <DateRangePicker.GridHead>
              <DateRangePicker.GridRow>
                {#each weekdays as day}
                  <DateRangePicker.HeadCell>
                    {day}
                  </DateRangePicker.HeadCell>
                {/each}
              </DateRangePicker.GridRow>
            </DateRangePicker.GridHead>
            <DateRangePicker.GridBody>
              {#each month.weeks as weekDates}
                <DateRangePicker.GridRow>
                  {#each weekDates as date}
                    <DateRangePicker.Cell {date} month={month.value}>
                      <DateRangePicker.Day>
                        {date.day}
                      </DateRangePicker.Day>
                    </DateRangePicker.Cell>
                  {/each}
                </DateRangePicker.GridRow>
              {/each}
            </DateRangePicker.GridBody>
          </DateRangePicker.Grid>
        {/each}
      {/snippet}
    </DateRangePicker.Calendar>
  </DateRangePicker.Content>
</DateRangePicker.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 { DateRangePicker } from "bits-ui";
  import { CalendarDateTime } from "@internationalized/date";
  let myPlaceholder = $state(new CalendarDateTime(2024, 8, 3, 12, 30));
</script>
 
<DateRangePicker.Root bind:placeholder={myPlaceholder}>
  <!-- ... -->
</DateRangePicker.Root>

Fully Controlled

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

	<script lang="ts">
  import { DateRangePicker } from "bits-ui";
  import type { DateValue } from "@internationalized/date";
  let myPlaceholder = $state<DateValue>();
 
  function getPlaceholder() {
    return myPlaceholder;
  }
 
  function setPlaceholder(newPlaceholder: DateValue) {
    myPlaceholder = newPlaceholder;
  }
</script>
 
<DateRangePicker.Root bind:placeholder={getPlaceholder, setPlaceholder}>
  <!-- ... -->
</DateRangePicker.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 { DateRangePicker } from "bits-ui";
  import { CalendarDateTime } from "@internationalized/date";
  let myValue = $state({
    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>
<DateRangePicker.Root bind:value={myValue}>
  <!-- ... -->
</DateRangePicker.Root>

Fully Controlled

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

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

Managing Open State

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

Two-Way Binding

Use bind:open for simple, automatic state synchronization:

	<script lang="ts">
  import { DateRangePicker } from "bits-ui";
  let isOpen = $state(false);
</script>
 
<button onclick={() => (isOpen = true)}>Open DateRangePicker</button>
 
<DateRangePicker.Root bind:open={isOpen}>
  <!-- ... -->
</DateRangePicker.Root>

Fully Controlled

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

	<script lang="ts">
  import { DateRangePicker } from "bits-ui";
  let myOpen = $state(false);
 
  function getOpen() {
    return myOpen;
  }
 
  function setOpen(newOpen: boolean) {
    myOpen = newOpen;
  }
</script>
 
<DateRangePicker.Root bind:open={getOpen, setOpen}>
  <!-- ... -->
</DateRangePicker.Root>

Customization

The DateRangePicker component is made up of three other Bits UI components: Date Range Field, Range Calendar, and Popover.

You can check out the documentation for each of these components to learn more about their customization options, each of which can be used to customize the DateRangePicker component.

API Reference

DateRangePicker.Root

The root date picker component.

Property Details
value
onValueChange
placeholder
onPlaceholderChange
readonlySegments
isDateUnavailable
minValue
maxValue
validate
onInvalid
granularity
hideTimeZone
errorMessageId
hourCycle
locale
disabled
readonly
required
closeOnRangeSelect
disableDaysOutsideMonth
pagedNavigation
preventDeselect
weekdayFormat
weekStartsOn
calendarLabel
fixedWeeks
isDateDisabled
numberOfMonths
open
onOpenChange
onOpenChangeComplete
onEndValueChange
onStartValueChange
minDays
maxDays
excludeDisabled
monthFormat
yearFormat
ref
children
child
Data Attribute Details
data-invalid
data-disabled
data-readonly
data-calendar-root

DateRangePicker.Label

The label for the date field.

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

DateRangePicker.Input

The field input component which contains the segments of the date field.

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

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

DateRangePicker.Trigger

A component which toggles the opening and closing of the popover on press.

Property Details
ref
children
child
Data Attribute Details
data-state
data-popover-trigger

DateRangePicker.Content

The contents of the popover which are displayed when the popover is open.

Property Details
side
sideOffset
align
alignOffset
arrowPadding
avoidCollisions
collisionBoundary
collisionPadding
sticky
hideWhenDetached
updatePositionStrategy
strategy
preventScroll
customAnchor
onInteractOutside
onFocusOutside
interactOutsideBehavior
onEscapeKeydown
escapeKeydownBehavior
onOpenAutoFocus
onCloseAutoFocus
trapFocus
preventOverflowTextSelection
forceMount
dir
ref
children
child
Data Attribute Details
data-state
data-popover-content
CSS Variable Details
--bits-popover-content-transform-origin
--bits-popover-content-available-width
--bits-popover-content-available-height
--bits-popover-anchor-width
--bits-popover-anchor-height

DateRangePicker.Portal

When used, will render the popover content into the body or custom to element when open

Property Details
to
disabled
children
Data Attribute Details

DateRangePicker.Calendar

The calendar component containing the grids of dates.

Data Attribute Details
data-invalid
data-disabled
data-readonly
data-calendar-root

The header of the calendar.

Property Details
ref
children
child
Data Attribute Details
data-disabled
data-readonly
data-range-calendar-header

DateRangePicker.PrevButton

The previous button of the calendar.

Property Details
ref
children
child
Data Attribute Details
data-disabled
data-range-calendar-prev-button

DateRangePicker.Heading

The heading of the calendar.

Property Details
ref
children
child
Data Attribute Details
data-disabled
data-readonly
data-range-calendar-heading

DateRangePicker.NextButton

The next button of the calendar.

Property Details
ref
children
child
Data Attribute Details
data-disabled
data-range-calendar-next-button

DateRangePicker.Grid

The grid of dates in the calendar, typically representing a month.

Property Details
ref
children
child
Data Attribute Details
data-disabled
data-readonly
data-range-calendar-grid

DateRangePicker.GridRow

A row in the grid of dates in the calendar.

Property Details
ref
children
child
Data Attribute Details
data-disabled
data-readonly
data-range-calendar-grid-row

DateRangePicker.GridHead

The head of the grid of dates in the calendar.

Property Details
ref
children
child
Data Attribute Details
data-disabled
data-readonly
data-range-calendar-grid-head

DateRangePicker.HeadCell

A cell in the head of the grid of dates in the calendar.

Property Details
ref
children
child
Data Attribute Details
data-disabled
data-readonly
data-range-calendar-head-cell

DateRangePicker.GridBody

The body of the grid of dates in the calendar.

Property Details
ref
children
child
Data Attribute Details
data-disabled
data-readonly
data-range-calendar-grid-body

DateRangePicker.Cell

A cell in the calendar grid.

Property Details
date
month
ref
children
child
Data Attribute Details
data-disabled
data-unavailable
data-today
data-outside-month
data-outside-visible-months
data-focused
data-selected
data-value
data-range-calendar-cell
data-range-start
data-range-end
data-range-middle
data-highlighted

DateRangePicker.Day

A day in the calendar grid.

Property Details
ref
children
child
Data Attribute Details
data-disabled
data-unavailable
data-today
data-outside-month
data-outside-visible-months
data-focused
data-selected
data-value
data-range-calendar-day
data-range-start
data-range-end
data-range-middle
data-highlighted

DateRangePicker.MonthSelect

A select you can use to navigate to a specific month in the calendar view.

Property Details
months
monthFormat
ref
children
child
Data Attribute Details
data-disabled
data-range-calendar-month-select

DateRangePicker.YearSelect

A select you can use to navigate to a specific year in the calendar view.

Property Details
years
yearFormat
ref
children
child
Data Attribute Details
data-disabled
data-range-calendar-year-select