New Components
Date picker
The date picker allows a date to be chosen from a visual calendar. It is built in two ways: the native date field, which delegates the calendar to the browser, and a field associated with a rebuilt calendar, opened in a dialog. The second is only worth it when the first cannot do the job: the calendar then follows the grid pattern, whose focus management has to be written in full.
When to use a date picker
- A precise date to enter: an arrival date, an appointment, a deadline.
- Unavailable dates to show: when some days are closed and the user has to see them before trying.
- Bearings in the calendar: when the answer depends on the day of the week or on how close another date is.
When not to use one
- A perfectly known date: for a date of birth, typing beats eighty clicks of navigation.
- A choice among a few dates: three slots present better as radio buttons.
- A month or a year alone: a full calendar to pick a month asks for needless work.
Modes of action
- Mouse: typing in the field, or opening the calendar and clicking a day.
- Keyboard: typing in the field stays possible from start to finish. Inside the grid, arrows change day, Page Up and Page Down change month, Escape closes.
- Screen reader: the native field is exposed with no effort. The bespoke calendar rests on role="dialog" and a grid whose every cell carries a full date.
Content
- The bounds, announced: the allowed period belongs in the hint, before entry.
- An example format: for a text field, show a full date, "31/12/2026", rather than an abstract template.
- Distinct errors: wrong format, non-existent date, date out of bounds, unavailable date; four situations, four messages.
On this page
Keywords
- input type="date": the native field, bringing the browser calendar, keyboard entry and the local format.
- role="dialog" and aria-modal: declare a modal dialog, which tabbing must not leave.
- Roving tabindex: inside a grid, one single cell is tabbable and the arrows move focus.
- aria-selected: the selection state. It has to sit on the element that receives focus.
Native date field
This is the first choice whenever the need does not call for a bespoke calendar.
- The order of the sub-fields follows the browser locale, never the lang attribute of the page. A hint announcing day, month, year would be wrong for some visitors: only the bounds are given.
- A partial entry leaves value empty but sets validity.badInput to true. Without that test, someone who can see their own entry on screen would be told "no date entered" (WCAG 3.3.1).
- The error and the success message do not travel the same channel: the error is bound to the field and read when focus lands, the success message is a live region.
Date field with a calendar
Only use it when the native field cannot do the job. The cost is real: the whole behaviour has to be written.
- Keyboard entry stays possible in the field. The calendar is a help, never the only path (WCAG 2.1.1).
- The calendar is a modal dialog: Escape closes it from anywhere and an outside click closes it too. Without those two precautions, focus can leave for a page that aria-modal declares hidden (WCAG 2.1.2 and 2.4.3).
- The cell itself is focusable, not a button placed inside it: aria-selected has to sit on the element that receives focus, otherwise the screen reader never says which day is chosen (WCAG 4.1.2).
- Every day carries a full accessible name, "15 June 2026", and unavailable days say so in their name: the information arrives on landing, not after a refused click.
- The component writes into the field by script, so it fires input and change, without which no form validation ever sees the value arrive.
Screen reader
- On the native field, no ARIA role is added: doubling it would produce a contradictory announcement.
- Inside the grid, the roving tabindex is real focus. It is never mixed with aria-activedescendant.
- A bare "15" means nothing: the accessible name of the cell carries the whole date.
- The month buttons do not steal focus and switch to aria-disabled when there is no allowed month left on that side.
The keyboard interactions differ according to the construction. With the native field, they are handled by the browser and vary from one engine to another. With a rebuilt calendar, they must be implemented in full.
Native date field
| Key | Function |
|---|---|
| Tab | Moves focus to the field, then from one segment to another depending on the browser. |
| Up and Down Arrow | Increment or decrement the active segment: day, month or year. |
| Left and Right Arrow | Move the cursor from one segment to another. |
| Numeric characters | Enter the active segment directly. |
| Space or Enter | Open the browser's calendar, where one is offered. |
Field associated with a calendar
| Key | Function |
|---|---|
| Tab | Moves focus to the field. The opening button is not a tab stop. |
| Down Arrow or Alt + Down Arrow | Open the calendar dialog. Focus is placed on the date in the field if it is valid, otherwise on today's date. |
| Text editing keys | Entering and correcting the date in the field. |
Calendar dialog
| Key | Function |
|---|---|
| Escape | Closes the dialog and returns focus to the field, without changing the value. |
| Tab | Moves focus to the next element in the dialog. The grid forms a single stop. On the last button, returns to the first. |
| Shift + Tab | Moves focus to the previous element. On the first button, goes to the last. |
| Space or Enter | On a navigation button, changes the month or year displayed. On the confirm button, retains the date and closes. On the cancel button, closes without retaining. |
Calendar grid
| Key | Function |
|---|---|
| Right Arrow | Moves focus to the next day. |
| Left Arrow | Moves focus to the previous day. |
| Down Arrow | Moves focus to the same day of the next week. |
| Up Arrow | Moves focus to the same day of the previous week. |
| Home | Moves focus to the first day of the current week. |
| End | Moves focus to the last day of the current week. |
| Page Up | Displays the previous month and places focus on the day with the same number, or on the last day of the month if that number does not exist. |
| Page Down | Displays the next month, following the same rule. |
| Shift + Page Up | Displays the same month of the previous year, following the same rule. |
| Shift + Page Down | Displays the same month of the next year, following the same rule. |
| Space | Retains the date and updates the value of the field, without closing the dialog. |
| Enter | Retains the date, updates the value of the field, closes the dialog and returns focus to the field. |
Note: the calendar grid uses a roving tabindex, and not aria-activedescendant: focus genuinely enters the grid and moves within it. This is the essential difference from dropdown lists with a list of options, where focus stays on the field. See the Dropdown list component page for those.
