Guide
The keyboard and screen readers
The most used jQuery time picker has had an issue titled "Time Picker accessibility issues" open for
years, and the usual answer elsewhere is a hidden <select>. This one is built from real controls.
The field
A real <input type="text"> — so a paste, a password manager and a phone keyboard all work —
marked up as a combobox:
| Attribute | What it does |
|---|---|
role="combobox" |
It is a field with a list attached. |
aria-expanded |
Whether the list is showing. |
aria-controls |
Points at the list. |
aria-activedescendant |
Which row the keyboard is on, without moving focus off the field. |
aria-autocomplete="list" |
Typing narrows what is offered. |
aria-invalid |
Set when what was typed is not a time, or not an available one. |
inputmode="numeric" |
The right keyboard on a phone. |
Focus never leaves the field while the list is open, so what you type keeps going where you are looking.
The keyboard
| Key | What it does |
|---|---|
| ↓ ↑ | Open the list, then move through the times that are available — stepping over the ones that are not. |
| Page Down / Page Up | Move by four steps. |
| Home / End | The first and last time on offer. |
| Enter | Take the highlighted time; or, with nothing highlighted, read what you typed. |
| Escape | Close the list and keep the value. |
| Tab | Close the list and move on. |
Tabbing into the field does not open the panel. A keyboard user moving through a form has not asked for a list yet, and one that opens by itself is something to escape from rather than a help. Clicking the field does open it, because that is what a click is for.
Enter with the list open applies the time and stops there. It does not submit the form the picker is sitting in — a small thing that pickers mounted inside forms get wrong.
The list
role="listbox"with onerole="option"per time andaria-selectedon the chosen one.- Times that cannot be picked carry
aria-disabled="true"and a visually hidden reason — "fully booked", "Not available" — so the row is not just mysteriously dead. - They stay in the list rather than disappearing. A list with the middle missing tells nobody anything; a list with 12:30 crossed out says the place is shut for lunch.
- A
role="status"live region announces a refusal and each nudge of the arrow keys.
On a phone
Small touch screens get a bottom sheet: full width, at the bottom where a thumb is, with rows at least 44px tall. Not a dropdown pinned to a field that the on-screen keyboard covers — which is the subject of open bugs in both of the libraries this replaces.
Seeing it
- Focus rings on every control, never colour alone.
@media (forced-colors: active)gives the panel system borders andHighlightfor the active row.- The sheet's entry animation is behind
prefers-reduced-motion. - Unavailable rows are struck through as well as greyed, so the difference is not only contrast.