Skip to content

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

NameTypeDefaultDescription
labelstringundefinedField label rendered above the trigger.
descriptionstringundefinedHelper text rendered below the trigger.
errorMessagestringundefinedValidation error rendered when the field is invalid.
tone'brand' | 'neutral' | 'danger'brandTone for the focus ring and the selected day in the calendar.
size'sm' | 'md' | 'lg'mdTouch target size matching every other helixui input.
valueDateValue | nullundefinedControlled selected date.
defaultValueDateValueundefinedUncontrolled initial selected date.
onChange(value: DateValue | null) => voidundefinedFires when the user picks a date in the grid or commits a segment edit.
minValueDateValueundefinedEarliest selectable date.
maxValueDateValueundefinedLatest selectable date.
isDateUnavailable(date: DateValue) => booleanundefinedMark specific dates as unselectable (blackout dates).
isDisabledbooleanfalseDisable the entire picker.
isReadOnlybooleanfalseShow 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

KeyAction
TabFocus the next segment or the trigger.
ArrowUpIncrement focused segment.
ArrowDownDecrement focused segment.
EnterOpen the popover from the trigger; select a focused day in the grid.
EscapeClose the popover.
ArrowKeysInside 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.
  • errorMessage is exposed via aria-describedby.