vaiperui

components / date-picker

DatePicker

Field that opens a Calendar to choose a day.

How to use

A button that looks like an `Input` shows the chosen day and opens a `Calendar`; choosing a day closes it. The date is not typed (for a typed date, use an `Input` with `mask="date"`). With `name`, the form receives `yyyy-mm-dd`. Focus enters the day on open and returns to the field on `Esc`.

preview
DatePicker.tsx
import { DatePicker } from "vaiperui";
const [date, setDate] = useState<Date>();
<DatePicker label="Delivery date" value={date} onValueChange={setDate} />
<DatePicker
label="Delivery date"
minDate={new Date()}
weekStartsOn={1}
locale="en-US"
/>

Sizes

preview
sm
md
lg
sizes.tsx
<DatePicker size="sm" />
<DatePicker size="md" />
<DatePicker size="lg" />

States

preview
Extra detail
helper
This is required
error
disabled
read only
states.tsx
<DatePicker label="..." helperText="..." />
<DatePicker label="..." errorMessage="..." />
<DatePicker label="..." disabled />
<DatePicker label="..." readOnly />

Limits

preview
min / max
limits.tsx
<DatePicker label="..." minDate={new Date(2026, 9, 10)} maxDate={new Date(2026, 9, 25)} />

Colors

preview
success
customColor
colors.tsx
<DatePicker variantColor="success" />
<DatePicker customColor="#ff6600" />

Props

PropValuesDefaultDescription
value / defaultValueDatenoneChosen day, controlled or initial
onValueChange(date: Date) => voidnoneCalled when a day is chosen
label / helperTextstringnoneLabel above the field and help text below
errorMessagestringnoneError text; its presence alone forces the error state
placeholderstringfrom the localeText when nothing is chosen (e.g. mm/dd/yyyy)
namestringnoneForm field name
disabled / readOnlybooleanfalseDoes not open the panel; readOnly still shows the value
variantring | outlineringFocus style, same as Input
size / radiussm | md | lg / none | sm | md | lg | fullmd / mdField height and corner rounding
aria-labelstringnoneAccessible name when there is no label
panelLabelstringnoneAccessible name of the open panel
minDate / maxDateDatenoneFirst and last allowed day; the rest and the month arrows leading outside are disabled
localestring"en-US"Language of month/day names and the date format (BCP 47)
weekStartsOn0 – 60First weekday (0 = Sunday)
previousMonthLabel / nextMonthLabelstring"Previous month" / "Next month"Accessible names of the month buttons
variantColor / customColor / animationprimary | success | warning | danger / CSS color / none | smooth | fast | bounceprimary / smoothColor of the selection and focus, and transition speed

Accessibility

  • The trigger is a `<button>` with `aria-haspopup="dialog"` and `aria-expanded` reflecting the panel state.
  • `label` is linked with `htmlFor`; without `label`, the trigger uses `aria-label`.
  • `errorMessage` sets `aria-invalid` and `aria-describedby` to the message; otherwise `helperText` is linked through `aria-describedby`.
  • The panel is a `role="dialog"` named by `panelLabel`, rendered in a portal on `document.body`.
  • `disabled` disables the button; `readOnly` keeps it focusable but the panel never opens.
  • Opening the panel focuses the selected day (or today) in the `Calendar`, which follows its grid pattern.

Keyboard

KeyAction
Enter / SpaceOpens or closes the panel from the trigger.
Arrow keys, Home, End, Page Up/DownNavigate the days inside the open panel (see Calendar); Enter or Space on a day picks it and closes the panel.
EscCloses the panel and returns focus to the trigger.

Keep in mind

  • The panel does not trap focus: Tab leaves it, and because it is rendered at the end of `<body>`, Tab from the trigger does not enter it on its own.
  • Clicking outside closes the panel without moving focus back; only Esc restores focus to the trigger.
  • The date cannot be typed: the only way to set it is the calendar. Use `Input` with `mask="date"` for typed dates.