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

When not to use it

Keyboard interactions

Role combobox, verified at WCAG 2.2-AA.

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" />

See the full DatePicker reference →