DatePicker
Anatomy
+-----------------------------------+| Label || +-------------------------------+ || | MM / DD / YYYY [📅] | | ← group: input + trigger| +-------------------------------+ || Helper text |+-----------------------------------+ ↓ trigger opens popover ↓+-----------------------------------+| ‹ May 2026 › || Su Mo Tu We Th Fr Sa || 27 28 29 30 1 2 3 || 4 5 6 7 8 9 10 || ... |+-----------------------------------+When to use
- Picking a single date where seeing the surrounding month helps (departure, due date, event date).
- Date inputs in larger forms where the user benefits from arrow-key navigation and a calendar.
When to reach for <DateField> instead
- You don’t want a popover (compact forms).
- The user is power-using a multi-field form and typing is faster.
Examples
Basic
<DatePicker label="Departure" />Controlled
import { parseDate, type DateValue } from '@internationalized/date';
const [d, setD] = useState<DateValue | null>(parseDate('2026-05-25'));<DatePicker label="Renewal" value={d} onChange={setD} />Blackout dates
const blocked = new Set(['2026-05-30', '2026-05-31']);<DatePicker label="Pickup" isDateUnavailable={(d) => blocked.has(d.toString())}/>Validation
<DatePicker label="Departure" isInvalid errorMessage="Departure must be in the future." tone="danger"/>Install: @helixui/core
import { DatePicker } from '@helixui/core'status: stable · since: 0.1.0
Tags: date, picker, popover, calendar, input
Props
| Name | Type | Default | Description |
|---|---|---|---|
label | string | undefined | Field label rendered above the trigger. |
description | string | undefined | Helper text rendered below the trigger. |
errorMessage | string | undefined | Validation error rendered when the field is invalid. |
tone | 'brand' | 'neutral' | 'danger' | brand | Tone for the focus ring and the selected day in the calendar. |
size | 'sm' | 'md' | 'lg' | md | Touch target size matching every other helixui input. |
value | DateValue | null | undefined | Controlled selected date. |
defaultValue | DateValue | undefined | Uncontrolled initial selected date. |
onChange | (value: DateValue | null) => void | undefined | Fires when the user picks a date in the grid or commits a segment edit. |
minValue | DateValue | undefined | Earliest selectable date. |
maxValue | DateValue | undefined | Latest selectable date. |
isDateUnavailable | (date: DateValue) => boolean | undefined | Mark specific dates as unselectable (blackout dates). |
isDisabled | boolean | false | Disable the entire picker. |
isReadOnly | boolean | false | Show the field as non-editable while still focusable. |
Tokens used
color.bg.input, color.bg.surface.default, color.bg.surface.subtle, color.bg.action.brand.default, color.bg.action.brand.subtle, color.border.subtle, color.border.action.brand, color.border.danger, color.text.primary, color.text.secondary, color.text.muted, color.text.action.brand, color.text.action.brand.on, color.text.danger, radius.sm, radius.md, radius.lg, shadow.lg, spacing.1, spacing.2, spacing.3, spacing.4, font.size.xs, font.size.sm, font.size.md, font.size.lg, font.weight.regular, font.weight.medium, font.weight.semibold
Accessibility
Role: combobox
Keyboard
| Key | Action |
|---|---|
Tab | Focus the next segment or the trigger. |
ArrowUp | Increment focused segment. |
ArrowDown | Decrement focused segment. |
Enter | Open the popover from the trigger; select a focused day in the grid. |
Escape | Close the popover. |
ArrowKeys | Inside the grid — move by day; PageUp/PageDown by month. |
Notes
- Each input segment is independently focusable.
- The trigger is a labeled
<button>that opens a dialog with the calendar. - The dialog traps focus while open and restores focus to the trigger on close.
- Days announce their selection state and unavailable state.
errorMessageis exposed viaaria-describedby.