Date Picker
A date input with a calendar popover — type a date or pick it from the month grid.
<DatePicker value={value} onChange={setValue} />Usage
DatePicker is a single, form-ready control: a DD/MM/YYYY text input with a trailing calendar button that opens the month grid. Type a date (digits auto-format with slashes) or pick one in the calendar — the two stay in sync. It speaks the native date contract (YYYY-MM-DD), so it drops straight into forms that previously used <input type="date">.
import { DatePicker } from "@reva/ui";It is fully controlled. Hold the value as a YYYY-MM-DD string ("" when empty) and update it from onChange:
const [value, setValue] = useState("");
<DatePicker value={value} onChange={setValue} />;Pass max to cap the latest selectable day (a date of birth can't be in the future, for example) and placeholder to override the default DD/MM/YYYY hint. The month/year dropdown caption makes distant dates — like dates of birth — quick to reach.
Examples
In a form field
Compose with Field for a label, hint, and error slot shared with other controls — this is the pattern used for "Date of birth" and "Incorporated on" across the product.
We use this to verify your identity.
<Field> <FieldLabel htmlFor="date-of-birth">Date of birth</FieldLabel> <DatePicker id="date-of-birth" value={value} onChange={setValue} max={todayISO} /> <FieldDescription>We use this to verify your identity.</FieldDescription></Field>Set max to keep selection in range — here future days are disabled and future typed dates are not committed.
Quick presets
Because the value is just a controlled string, sibling controls can write to it. Here preset buttons set the date that the input and calendar both read from.
<VStack gap={2}> <HStack gap={2}> <Button onClick={() => setValue(isoFromToday(0))} size="sm" variant="secondary"> Today </Button> <Button onClick={() => setValue(isoFromToday(7))} size="sm" variant="secondary"> +1 week </Button> <Button onClick={() => setValue(isoFromToday(30))} size="sm" variant="secondary"> +1 month </Button> </HStack> <DatePicker value={value} onChange={setValue} /></VStack>Reading the selected value
onChange emits the ISO YYYY-MM-DD string, ready for summaries, mutation payloads, or other fields.
Selected value: 2026-03-01
<VStack gap={3}> <DatePicker value={value} onChange={setValue} /> <Text color="muted-foreground" size="sm"> Selected value: {value || "—"} </Text></VStack>Date range
There is no range component — DatePicker is single-only. For a range, compose a Popover and a Calendar in mode="range", triggered by a Select-styled control that reads back the chosen span. See Calendar for mode, numberOfMonths, and selected / onSelect.
<Popover> <PopoverTrigger asChild> <button className={cn(selectTriggerVariants({ variant: "default" }), "w-full justify-between")} type="button" > <span>{formatRangeLabel(range)}</span> <CaretDown className="size-4 shrink-0 text-fg-muted" /> </button> </PopoverTrigger> <PopoverContent align="start" className="w-auto overflow-x-auto p-0"> <Calendar mode="range" numberOfMonths={2} selected={range} onSelect={setRange} /> </PopoverContent></Popover>Reusing selectTriggerVariants keeps the trigger visually identical to a Select while the calendar drives the selection.
Props
DatePicker is the single-date control. Range selection is composed from Calendar and Popover.
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | — | Controlled value as a YYYY-MM-DD string ("" when empty). Required. |
onChange | (value: string) => void | — | Fires with the new YYYY-MM-DD string, or "" when the field is cleared. Required. |
placeholder | string | "DD/MM/YYYY" | Placeholder text for the empty input. |
max | string | — | Latest selectable date, inclusive, as YYYY-MM-DD. Later days are disabled and later typed dates are not committed. |
id | string | — | Forwarded to the input — pair with FieldLabel htmlFor for an accessible label. |