Date Picker
Click-to-open trigger, styled like an Input, that reveals a Calendar panel in a popover.
Description
DatePicker is a compound component: DatePicker.Trigger renders a button styled with the same Input shell used across the form components, and DatePicker.Content anchors a Radix popover panel below it. The component has no opinion on what goes inside that panel. You fill it with Calendar, so whichever mode the calendar runs in, single, multiple, or range, is what the picker does.
Reach for it any time a date field should be picked from a grid instead of typed. It reads naturally as a filter trigger ("Last 30 days"), a booking field, or a due-date picker on a form, anywhere a typed date would force the user to remember a format.
If the user types the date directly, use Date Input instead, a masked DD/MM/YYYY field. If the calendar should always be visible rather than sitting behind a trigger, drop the trigger and render Calendar on its own.
DatePicker is a Create UI Pro component. With a Pro seat, npx @create-ui/cli add date-picker installs it, and the previews on this page are marked with a Pro badge. It pulls in Calendar and Button for the composed examples below.
Installation
Anatomy
DatePicker.Content is unstyled: no background, border, or padding of its own. All of the panel's visual chrome comes from Calendar.Panel, so it always needs to wrap whatever Calendar composition sits inside DatePicker.Content. A bare <Calendar /> with no panel floats with nothing behind it.
Usage
Examples
Five examples: sizes and states cover the trigger's own props, then two compositions, single date and date range with presets, show how the closing behavior changes with Calendar's mode.
Sizes
size on the DatePicker root drives the trigger's Input shell height (xs, sm, md). It has no effect on the Calendar panel itself. Size that one separately if you want the grid to scale too.
States
invalid recolors the trigger's text and icon without touching the panel. disabled sets the native disabled attribute on the trigger button, so the popover can't open, and tints the shell to the disabled visual.
Single date
A single click is a complete choice, so there's nothing to confirm. Control open yourself and close it straight from Calendar's onChange, no footer, no Apply button.
Date range with presets
Calendar.Presets gives the range picker shortcuts like "Last 7 days" next to the grid. A range needs two clicks to complete, so Apply and Clear live in Calendar.Footer and only Apply closes the popover.
Accessibility
ARIA notes:
DatePicker.Triggerrenders a real<button>wrapped in Radix'sPopover.Trigger, so it picks uparia-expandedandaria-haspopupautomatically as the popover opens and closes.- The trigger sets no
aria-invaliditself.invalidis a purely visual recolor, since the trigger is a button that opens a picker, not an editable field carrying its own validation state. DatePicker.Contentis Radix'sPopover.Content, so focus trapping, dismiss-on-outside-click, andEscape-to-close all come from Radix's tested popover behavior.- Whatever you compose inside
DatePicker.Contentkeeps its own accessibility contract. WithCalendar, that means React Aria's grid semantics, roving tabindex, and selection announcements. See Calendar's accessibility notes for the day-grid details.
Styling
Tailwind override: pass className to DatePicker.Trigger to merge Tailwind classes with the component's classes (via cn()):
Data slots and attributes:
data-slot="date-picker"on the root.data-slot="date-picker-trigger"on theInput-shell wrapper,data-slot="date-picker-trigger-button"on the underlying<button>.data-slot="date-picker-content"on the popover panel,data-slot="date-picker-close"onDatePicker.Close.data-state="open"/data-state="closed"on the trigger and content, mirrored from Radix Popover.data-sideondate-picker-content, reflecting which side of the trigger the panel actually rendered on.
Target the trigger's invalid state in CSS:
Related Components
- Calendar: the grid that fills
DatePicker.Content. Use it alone when the calendar should stay visible instead of sitting behind a trigger. - Date Input: a masked, typed date field. Use it when the user knows the date and would rather type it than click through months.
- Popover: the primitive
DatePicker.Contentis built on. Reach for it directly when the trigger isn't a date field. - Select: for picking from a short list of options rather than a date.
API Reference
DatePicker
The root. Renders Radix's Popover.Root and opens the context every other part reads size, invalid, disabled, and loading from. Extends React.ComponentProps<typeof Popover.Root>.
Props
DatePicker.Trigger
The clickable, Input-styled button that opens the popover. Extends Omit<React.ComponentProps<typeof Popover.Trigger>, "asChild">.
Props
Variants
DatePicker.Content
The popover panel. Extends React.ComponentProps<typeof Popover.Content>.
Props
DatePicker.Close
A thin re-export of Radix's Popover.Close, for closing the popover from inside DatePicker.Content (an Apply button, for example). Extends React.ComponentProps<typeof Popover.Close>.
Props
Types
InputSize comes from Input. useDatePickerContext() reads the current DatePickerContextValue, useful for a custom trigger replacement that still wants to follow the root's size / invalid / disabled state.