Date Picker
A button that opens a calendar in a popover, for picking a single date in forms and filters.
The Date Picker is a Calendar tucked inside a popover. It takes little space until someone needs it, then closes as soon as they pick a day.
Preview
Usage
import { z } from 'zod'
import { AutoForm } from '@vitnode/core/components/form/auto-form'
import { AutoFormDatePicker } from '@vitnode/core/components/form/fields/date-picker'const formSchema = z.object({
birthday: z.iso.date('Pick your birthday'),
anniversary: z.iso.date().optional(),
})
<AutoForm
formSchema={formSchema}
fields={[
{
id: 'birthday',
component: props => (
<AutoFormDatePicker {...props} label="Birthday" />
),
},
{
id: 'anniversary',
component: props => (
<AutoFormDatePicker {...props} label="Community anniversary" />
),
},
]}
/>The value is a YYYY-MM-DD string, so use z.iso.date() in the schema. It is the user's local day, with no time zone surprises on the way to your API. Optional fields get a Clear button.
z.date() does not work in AutoForm: the schema is turned into JSON Schema,
which has no date type. Use z.iso.date() and convert on the server if you
need a Date.
Calendar options
calendarProps passes any Calendar prop through, except the selection ones. A birthday field with year dropdowns and no future dates:
<AutoFormDatePicker
{...props}
calendarProps={{
captionLayout: 'dropdown',
disabled: { after: new Date() },
endMonth: new Date(),
startMonth: new Date(1926, 0),
}}
label="Birthday"
/>Date format
The button shows the date in the active VitNode language, October 7, 2026 in English. Pass Intl.DateTimeFormat options to change it.
<DatePicker
dateFormat={{ dateStyle: 'short' }}
onChange={setDate}
value={date}
/>Date range
DateRangePicker picks a start and an end day. Quick ranges on the left apply in one click; a range picked on the calendar waits for Apply range, so a half-finished pick never fires a request. The button shows the preset's name, or the dates like Oct 7 – 12, 2026.
import { DateRangePicker } from '@vitnode/core/components/ui/date-range-picker'const [range, setRange] = React.useState({ from: weekAgo, to: today })
const [preset, setPreset] = React.useState<'7d' | '30d' | null>('7d')
<DateRangePicker
activePreset={preset}
disabledDays={{ after: today }}
endMonth={today}
onChange={next => {
setPreset(null)
setRange(next)
}}
onPresetSelect={next => {
setPreset(next)
setRange(resolve(next))
}}
presets={[
{ key: '7d', label: 'Last 7 days' },
{ key: '30d', label: 'Last 30 days' },
]}
value={range}
/>You own the presets: onPresetSelect hands you the key and you work out the dates, so "Last 7 days" can mean the site's time zone instead of the browser's. The calendar shows two months on wide screens and one on phones.
Accessibility
AutoFormDatePickerwires the label, description and error to the button.- With
DatePickeralone, give it anidand a<Label htmlFor>. - Opening the popover moves focus into the calendar. Escape closes it and focus returns to the button.
- A validation message waits until focus leaves the field, not when the popover opens.
Props
DatePicker
DatePicker also takes every <button> prop.
Prop
Type
AutoFormDatePicker takes the same props, except its onChange receives the YYYY-MM-DD string.
DateRangePicker
DateRangePicker also takes every <button> prop.
Prop
Type