Skip to main content

ScrollField

MD3 Expressive scroll field (Compose's ScrollField): a vertical wheel of numbers that wraps around endlessly and snaps the selected value to its centre. It is the building block of the TimePicker's scroll mode, and works on its own for any small integer range.

Basic usage​

min (default 0) and max set the range; max wraps back to min. Use value + onChange(event, value) for a controlled field or defaultValue for an uncontrolled one. Values are drawn zero-padded to two digits; the centred one is DisplayLarge Emphasized in OnSurface, its neighbours DisplayMedium in Outline.

Selected: 30
const [minute, setMinute] = useState(30)

<ScrollField
aria-label="Minute"
max={59}
value={minute}
onChange={(event, value) => setMinute(value)}
getValueText={(value) => `${value} minutes`}
/>

Size and formatting​

The field is 100×200px by default (Compose's ScrollFieldHeight); each value takes a third of 200px whatever height you give it, so a shorter field shows less of the neighbours. Set width / height with style or className. formatValue changes how values are drawn.

<ScrollField aria-label="Year" min={2000} max={2030} formatValue={String} style={{ width: 160 }} />
<ScrollField aria-label="Hour" min={1} max={12} style={{ height: 120 }} />
<ScrollField aria-label="Disabled" max={59} disabled />

Accessibility​

  • The field is an ARIA spinbutton with aria-valuenow, aria-valuemin, aria-valuemax and aria-valuetext. Give it a name with aria-label (or aria-labelledby), and pass getValueText when the number alone is not enough (for example "7 o'clock").
  • Keyboard: ArrowUp / ArrowDown move by one value and wrap around, PageUp / PageDown by pageStep (default 5), Home / End jump to min / max.
  • The mouse wheel moves one value per notch without scrolling the page. Dragging (touch, mouse or pen) scrolls the wheel and snaps to the nearest value, and tapping a neighbouring value scrolls to it.
  • With reduced motion the wheel jumps instead of animating.

Props​

PropTypeDefaultDescription
defaultValuenumberminUncontrolled initial value.
disabledbooleanfalseDisabled: dimmed colors, no interaction, out of the Tab order.
formatValue((value: number) => string)(n: number) => String(n).padStart(2, '0')Text drawn for a value.
getValueText((value: number) => string)formatValue's resultaria-valuetext for a value — include the unit (e.g. "7 o'clock").
max *number—Largest value (inclusive). The wheel wraps from max back to min.
minnumber0Smallest value.
onChange((event: Event, value: number) => void)—Fires with the new value as the wheel moves (keyboard, wheel, drag, tap). The event is the native event behind the change.
pageStepnumber5Values moved by PageUp / PageDown.
valuenumber—Controlled value (an integer from min to max).