Date Picker

PreviousNext

An editable date field with a calendar in a popover — type it or pick it.

Installation

pnpm dlx shadcn@latest add https://matos-ui.com/r/date-picker.json

Usage

import { DatePicker } from '@/components/matos-ui/date-picker'
const [date, setDate] = useState<Date | null>(null)

<DatePicker value={date} onValueChange={setDate} />

Examples

Bounded, in a form

<form action={submit}>
  <DatePicker name="starts" defaultValue={new Date()} min={new Date()} />
  <button type="submit">Save</button>
</form>

The hidden input posts ISO yyyy-mm-dd.

A custom display format

<DatePicker
  format={(d) => d.toLocaleDateString('en-GB', { dateStyle: 'medium' })}
/>

How it's built

  • Type it or pick it. The <input> takes ISO yyyy-mm-dd or the locale's numeric form — 11/22/2033 under en-US, 22/11/2033 under en-GB, the field order read from Intl.DateTimeFormat. No natural language. It parses on blur and on Enter; an unparseable value flags the field (aria-invalid) rather than clearing what you typed.
  • The popover rides the ladder. surfaceClasses(useSurface() + 2) — two rungs above wherever the field sits, the dropdown convention — so it never disappears into a dialog it opens inside. No bg-popover.
  • Focus is Base UI's job. The popover is @base-ui/react/popover (through the Popover component): it moves focus into the grid on open and back to the calendar button on close, traps it while open, and closes on Esc and outside-click.
  • Picking closes. Selecting a day fills the input, closes the popover, and the calendar keeps whatever month you'd navigated to.
  • Everything else — the six-row grid, the sliding month change, the keyboard — is the Calendar underneath.

Reference

DatePicker Props

PropTypeDefaultDescription
valueDate | nullControlled selection.
defaultValueDate | nullnullInitial selection when uncontrolled.
onValueChange(value: Date | null) => voidFires with the picked or parsed date.
placeholderstring"Select a date"Input placeholder.
format(date: Date) => stringIntl long dateRender the value in the input.
parse(input: string, locale: string) => Date | nullISO + numericParse what the reader typed.
namestringHidden input name; posts ISO yyyy-mm-dd.
min / maxDate | nullSelectable bounds (also enforced on typed input).
isDateDisabled(date: Date) => booleanDisable specific dates.
weekStartsOnnumberlocale's first day0 (Sunday) – 6 (Saturday).
localestring"en-US"BCP-47 tag for names and numeric parsing.
disabled / readOnlybooleanfalse
open / defaultOpen / onOpenChangeControl the popover.