How to build an accessible DatePicker in React
The field is an <input role="combobox"> with aria-expanded, aria-controls and aria-haspopup="dialog" that accepts a typed date — the previous build had no text field at all, so a date already known could only be reached by paging a grid. ArrowDown and Alt+ArrowDown open the popup (the combobox pattern's required key, listed in the old manifest but never implemented), opening moves focus into the grid and Escape closes and returns it to the field; the old build did neither, leaving the grid unreachable on open and focus on <body> on close. The grid itself is a composed Calendar rather than a second hand-rolled copy, so its real-focus navigation, min/max clamping, disabled-day skipping, aria-selected placement and month announcements all apply here; the duplicate had none of them and its arrow keys did nothing at all until a value was set. Dismissal comes from the shared DismissableLayer instead of a raw document listener. Typed input is parsed at commit, not per keystroke, and rejected rather than coerced when unreadable or out of bounds.
When to use a DatePicker
- Picking a single calendar date in a form where a visual month grid helps (due dates, bookings)
- Date entry that benefits from min/max constraints and locale-aware formatting and week start
When not to use it
- Selecting a time of day — use TimePicker
- Free-form or approximate dates where a plain Input is faster, or a date already known by typing
Keyboard interactions
Role combobox, verified at WCAG 2.2-AA.
ArrowDownArrowUpArrowLeftArrowRightHomeEndPageUpPageDownEnterSpaceEscapeDelete
Common mistakes
Avoid: Passing a localized display string as value
Prefer: value/defaultValue/min/max are ISO YYYY-MM-DD; display formatting is handled internally
The component parses and compares ISO dates; non-ISO values break selection, constraints, and onValueChange
Example
<DatePicker label="Date" />