Date & Time

DateRangePicker

Start and end segmented inputs in one field, backed by a two-month range calendar. Constrain the span with minDays/maxDays and add per-endpoint time entry.

Playground

Experiment with different props in real-time.

Basic Usage

Bind a DateRange with start and end.

<script lang="ts">
  import { DateRangePicker } from 'sv5ui';
  import { today, getLocalTimeZone } from '@internationalized/date';
  import type { DateRange } from 'bits-ui';

  const now = today(getLocalTimeZone());
  let value = $state<DateRange>({ start: now, end: now.add({ days: 4 }) });
</script>

<DateRangePicker bind:value />

Day Constraints

Limit the length of the selected range.

<!-- Enforce a 3 to 10 night stay -->
<DateRangePicker minDays={3} maxDays={10} />

Time Input

Set timeInput to add start and end time fields below the calendar.

<!-- Start and end time fields below the calendar -->
<DateRangePicker timeInput />

Single Month

<!-- One month instead of the default two -->
<DateRangePicker numberOfMonths={1} />

Min & Max

<script lang="ts">
  import { DateRangePicker } from 'sv5ui';
  import { today, getLocalTimeZone } from '@internationalized/date';

  const now = today(getLocalTimeZone());
</script>

<DateRangePicker minValue={now} maxValue={now.add({ months: 2 })} />

Variants

<DateRangePicker variant="outline" />
<DateRangePicker variant="soft" />
<DateRangePicker variant="subtle" />
<DateRangePicker variant="ghost" />

Sizes

<DateRangePicker size="xs" />
<DateRangePicker size="md" />
<DateRangePicker size="xl" />

Form Field

The range submits as {name}-start and {name}-end hidden inputs.

Please pick a date range

<script lang="ts">
  import { DateRangePicker, FormField } from 'sv5ui';
  import type { DateRange } from 'bits-ui';

  let range = $state<DateRange | undefined>(undefined);
  const error = $derived(
    range?.start && range?.end ? '' : 'Please pick a date range'
  );
</script>

<FormField label="Stay dates" {error}>
  <!-- Submits {name}-start and {name}-end hidden inputs -->
  <DateRangePicker bind:value={range} name="stay" />
</FormField>

UI Slots

Use the ui prop to override classes. Pass ui.calendarSlots to reach the calendar's own slots.

SlotDescription
rootThe field wrapper
fieldThe field container
inputThe start and end segmented inputs
separatorThe icon between the two inputs
triggerThe calendar popover trigger button
contentThe popover content
calendarThe two-month range calendar
timeThe time-input row (when timeInput is set)

Props

PropTypeDefault
valueDateRange-
onValueChange(value) => void-
placeholderDateValuecurrent date
openbooleanfalse
minDaysnumber-
maxDaysnumber-
granularity'day' | 'hour' | 'minute' | 'second''day'
localestring'en'
minValueDateValue-
maxValueDateValue-
isDateDisabledDateMatcher-
excludeDisabledbooleanfalse
timeInputbooleanfalse
closeOnRangeSelectbooleantrue
numberOfMonthsnumber2
separatorIconstring'lucide:minus'
iconstring'lucide:calendar'
variant'outline' | 'soft' | 'subtle' | 'ghost' | 'none''outline'
calendarVariant'solid' | 'outline' | 'soft' | 'subtle''solid'
colorColorType'primary'
size'xs' | 'sm' | 'md' | 'lg' | 'xl''md'
disabledbooleanfalse
readonlybooleanfalse
requiredbooleanfalse
namestring-
refHTMLElement | nullnull
classstring-
uiRecord<Slot, Class>-