How to build an accessible WheelPicker in React
The column is a role="listbox" with role="option" rows, is focusable, and points aria-activedescendant at the selected row, so assistive technology tracks the selection without moving DOM focus per row. Selection follows focus — ArrowUp/ArrowDown, Home/End and PageUp/PageDown move the selection and scroll to match — which is the APG single-select listbox variant that needs no explicit commit; the pattern is deliberately not declared as `apgPattern: listbox` because that guard requires an Enter key this variant has nothing to bind. The wheel itself is CSS scroll-snap, so touch momentum and rubber-banding are the platform's own and remain correct under assistive gestures. Smooth scrolling is applied only under prefers-reduced-motion: no-preference. The selection band is decorative and aria-hidden.
When to use a WheelPicker
- Touch surfaces picking one value from a short, ordered, homogeneous range — an hour, a minute, a unit
- Mobile forms following the platform convention of a drum rather than a dropdown
- Inside a BottomSheet or ActionSheet, where a native select would open a competing overlay
When not to use it
- Long or unordered option lists, where scrolling to a value is slower than typing — use Combobox
- Desktop, pointer-first forms — use Select or NativeSelect
- Dates, which have their own affordances — use DatePicker or Calendar
Keyboard interactions
Role listbox, verified at WCAG 2.2-AA.
ArrowUpArrowDownHomeEndPageUpPageDownTab
Common mistakes
Avoid: Rendering it uncontrolled and reading the value from the DOM
Prefer: Pass `value` and `onValueChange`
The component is controlled; without a `value` it cannot scroll to the current selection or reflect an external change
Avoid: Leaving `ariaLabel` off a wheel with no visible label
Prefer: Label every column — "Hour", "Minute"
A listbox with no accessible name is announced only as a list, so the user cannot tell which field they are in
Example
<WheelPicker
ariaLabel="Hour"
value={hour}
onValueChange={setHour}
options={[
{ value: '09', label: '09' },
{ value: '10', label: '10' },
{ value: '11', label: '11' },
]}
/>