DatePicker
A button or text field that picks one date from a Calendar in a popover.
Basic
A button that shows the date and opens a calendar. Picking a day closes it and returns focus.
value: none
events: none
Code
<DatePicker value={form.due} />Usage
import { DatePicker } from "@elements/ui/date-picker";
<DatePicker value={form.due} />
<DatePicker value={form.due} input name="due" required />
<DatePicker value={person.dob} captionLayout="dropdown" startMonth="1900-01" max={today} />Examples
Modal
modal makes the popover a modal dialog, as the WAI-ARIA date picker dialog is: Tab cycles inside it and the page behind is hidden from assistive tech.
value: none
Code
<DatePicker value={form.due} modal />Date of birth
Month and year dropdowns reach a date decades back without paging. Nothing after today.
value: none
Code
<DatePicker value={person.dob} captionLayout="dropdown"
startMonth="1900-01" max={today} placeholder="Select date" />Two months
numberOfMonths shows months side by side, each with its own dropdowns. On a phone the popover shows one, the month focus is in.
value: 2026-10-12
Code
<DatePicker value={trip.start} numberOfMonths={2} captionLayout="dropdown" />Input
Type a date in your locale's format or as ISO, or press ArrowDown or the calendar button to pick one.
value: 2026-10-14
Code
<Field label="Subscription date">
<DatePicker value={form.date} input />
</Field>Natural language
natural reads English phrases as dates: tomorrow, in 3 days, next friday, dec 25. The text stays as typed and the calendar shows the date it means.
Your post will be published on no date yet.
Code
<Field label="Schedule date">
<DatePicker value={post.date} input natural placeholder="Tomorrow or next week" />
</Field>
<p>Your post will be published on {longDate(post.date)}.</p>Input with an inline calendar
A typed date selects the day and moves the calendar to its month; a picked day fills the field. clearOnInvalid empties the selection while the text is not a date.
Code
<Field label="Booking date">
<DatePicker value={booking.date} input clearOnInvalid
onValueChange={(d) => booking.month = d || booking.month} />
</Field>
<Calendar value={booking.date} month={booking.month} footer={picked(booking.date)}
onValueChange={(d) => booking.month = d} />Dialog with OK and Cancel
The WAI-ARIA date picker dialog: a modal calendar with previous and next year buttons, and OK, which picks the focused day, and Cancel, which leaves the date as it was.
(date format: mm/dd/yyyy)
value: none
events: none
Code
<Field label="Date" description="(date format: mm/dd/yyyy)">
<DatePicker value={form.date} input modal actions yearButtons calendarLabel="Choose Date" changeLabel="Change Date"
help="Cursor keys can navigate dates" />
</Field>Limits
From today to the end of January, weekdays only. Typed dates outside are refused.
value: none
Code
<DatePicker value={form.date} min={today} max="2027-01-31"
disabledDates={{ dayOfWeek: [0, 6] }} />Format and locale
format takes Intl options; locale sets the language of the text and the calendar.
Code
<DatePicker value={a} format={{ dateStyle: "full" }} />
<DatePicker value={b} locale="de-DE" format={{ day: "numeric", month: "short", year: "numeric" }} />Presets
The footer slot sits under the calendar: quick picks set the date and close.
value: none
Code
<DatePicker value={state.date} open={state.open}>
<div slot="footer" class="presets">
<Button e:for={p of PRESETS} size="sm" onclick={() => setPreset(state, p.days)}>{p.label}</Button>
</div>
</DatePicker>Date and time
A TimePicker in the footer sets the time; picking the day closes the popover.
moment: none
Code
<DatePicker value={meeting.date} format={{ dateStyle: "medium" }}>
<div slot="footer">
<TimePicker value={meeting.time} block label="Time" />
</div>
</DatePicker>In a form
name submits the ISO date; required blocks the submit and brings focus to the picker.
not submitted
Code
<form onsubmit={(e) => save(e)}>
<DatePicker value={form.due} name="due" required />
<Button type="submit">Save</Button>
</form>Typed, in a form
Enter in the text field submits the date it shows, a two digit year included. The form posts start and nothing else.
not submitted
Code
<form onsubmit={(e) => save(e)}>
<DatePicker value={trip.start} input name="start" />
<Button type="submit">Save</Button>
</form>In a field
Field labels the picker, describes it and shows its error.
Code
<Field label="Due date" description="When the invoice is due." required>
<DatePicker value={invoice.due} />
</Field>Sizes and states
Three sizes from the control tokens, disabled, read only and invalid. A disabled picker's value is not submitted; a read only one's is.
Code
<DatePicker size="sm" />
<DatePicker size="lg" />
<DatePicker value="2026-10-14" name="closed" disabled /> <!-- not submitted -->
<DatePicker value="2026-10-14" name="fixed" readOnly /> <!-- submitted -->
<DatePicker invalid />Controlled
open is two-way. closeOnSelect=false keeps the calendar open while you pick.
open: false; events: none; value: none
Code
<DatePicker value={state.date} open={state.open} closeOnSelect={false}
onOpenChange={(open) => log(open)} />
<Button onclick={() => state.open = true}>Open from anywhere</Button>Calendar options
Every Calendar option passes through: here month opens on February 2027, navLayout puts both buttons after the caption, hideWeekdays drops the header row, and onMonthChange reports paging.
month: none
Code
<DatePicker month="2027-02" navLayout="after" hideWeekdays
onMonthChange={(m) => state.shown = m} />Other calendars
calendar passes to the Calendar and the text: here the Persian calendar in English. The button shows the Persian date, a typed date is read in Persian years and months, and the value stays a Gregorian ISO date.
value: 2026-10-30; typed: none
Code
<DatePicker calendar="persian" locale="en-US" value={trip.day} />
<DatePicker calendar="persian" locale="en-US" input value={trip.day} /> <!-- type 08/18/1405 or Azar 1, 1405 -->Time zone
timeZone passes to the Calendar: today, where the calendar opens and focus lands, is the date in that zone.
Code
<DatePicker timeZone="Pacific/Kiritimati" /> <!-- today is the date in Kiritimati -->Right to left
Arabic, right to left: the popover aligns to the start, the calendar reads right to left, and labels name the month buttons in Arabic.
Code
<div dir="rtl">
<DatePicker locale="ar-EG" dir="rtl" placeholder="اختر تاريخًا"
labels={{ previous: "الشهر السابق", next: "الشهر التالي" }} />
</div>