Skip to main content
Urbicon UI
source

DateRangePicker

A calendar popover for picking a start and end date, for travel dates, a booking window, or a reporting period. It builds on DatePicker: same sizes, variants, constraints, and locale handling.

Playground

Input Variant
Calendar Variant
<DateRangePicker
  label="Travel dates"
/>

01 Examples

Booking a stay

Two clicks on one dual calendar: the first sets the start, the second the end. closeOnSelect (the default) dismisses the popover once the range is complete, so the flow ends without a second gesture.
<script>
  import { DateRangePicker, type DateRange } from '@urbicon-ui/blocks';
  let stay = $state<DateRange | undefined>(undefined);
</script>

<DateRangePicker
  label="Check-in / check-out"
  bind:value={stay}
  placeholder="Pick your dates"
  clearable
/>

Bounded to a bookable window

minDate and maxDate fence the calendar; isDateDisabled blocks the irregular gaps a fixed range cannot express, here every Sunday.
Next 90 days, Sundays excluded
<script>
  import { DateRangePicker, type DateRange } from '@urbicon-ui/blocks';
  let bookable = $state<DateRange | undefined>(undefined);
  const TODAY = new Date(2026, 7, 3);
  const IN_90_DAYS = new Date(2026, 10, 1);
</script>

<DateRangePicker
  label="Bookable period"
  bind:value={bookable}
  minDate={TODAY}
  maxDate={IN_90_DAYS}
  isDateDisabled={(d) => d.getDay() === 0}
  helper="Next 90 days, Sundays excluded"
/>

Reporting period in a form

name writes two hidden inputs, period_start and period_end, each carrying the serialised date, so the submitted form has the ISO values, not the locale-formatted display text. An empty range submits both as an empty string.
Submitted as period_start and period_end
<script>
  import { DateRangePicker, type DateRange } from '@urbicon-ui/blocks';
  let reportRange = $state<DateRange | undefined>(undefined);
</script>

<DateRangePicker
  label="Reporting period"
  name="period"
  bind:value={reportRange}
  required
  helper="Submitted as period_start and period_end"
/>

02 Customization

The trigger and the calendar are styled separately: inputVariant takes the Input ladder (outlined, filled, ghost, underline) and calendarVariant the Calendar one (default, bordered, ghost). size applies to both.

The calendar props pass straight through: locale, weekStartsOn, showWeekNumbers, showOutsideDays, fixedWeeks. locale defaults to 'auto', which follows the active <I18nProvider>, so an app that already declares its language does not repeat it here.

For a single date use DatePicker; for the calendar without an input, see Calendar. See Customization for the general contract.

03 Accessibility

Popup state on the trigger

The text input carries aria-haspopup="dialog", aria-expanded, and (while open) aria-controls pointing at the calendar, so assistive tech reports both that a calendar exists and whether it is showing.

Keyboard

opens the calendar from the field. Enter closes it while open, and commits what has been typed while it is not. Esc closes the calendar; pressed again on a field with an uncommitted draft it discards that draft rather than the selection. Grid navigation inside the calendar follows the Calendar pattern.

Both embedded buttons are named

When clearable is set the field carries two controls, and each gets its own localized aria-label: "clear input" and "open calendar". Both keep a visible focus-visible ring.

Typing is a first-class path

The range can be typed as well as clicked; parsing happens on blur or Enter, and a parse failure shows as the field's error.

Dismissal is separable from notification

closeOnEscape and closeOnClickOutside govern whether the popover closes; onEscape and onClickOutside only tell you it happened.

04 API Reference

38 props
38 props
Prop
Type
Default
Description

05 Types

Local type definitions used by this component.

14 types
Name
Kind
Category
Used by
Description

06 Installation

Import

import { DateRangePicker } from '@urbicon-ui/blocks';