How to build an accessible Calendar in React

Renders an APG-compliant role="grid" table with role="row"/role="gridcell"; a roving tabindex keeps exactly one day focusable (the focused date) so arrow keys move focus per APG, Home/End jump to the week edges, PageUp/PageDown change month (with Shift for year), today exposes aria-current="date", selection sets data-selected with aria-selected on the cell, and out-of-range or predicate-disabled days get aria-disabled and are skipped by selection

When to use a Calendar

When not to use it

Keyboard interactions

Role grid, verified at WCAG 2.2-AA.

Common mistakes

Avoid: Comparing dates with local-time getters (getHours/getDate) after constructing them with new Date(y, m, d)

Prefer: All arithmetic and comparisons use UTC getters/Date.UTC so DST and timezone offsets never shift a day

Local-time construction can land a midnight date on the previous day in negative-offset zones, breaking selection and range math

Example

<Calendar defaultValue={new Date(Date.UTC(2024, 5, 15))} />

See the full Calendar reference →