Quantity
Forms
Open in Storybook: Quantity (opens in a new tab)
Overview
A compact control for a number the user steps through, like the items of a cart. It is one native input (type="number", role="spinbutton", inputmode="numeric") between two buttons that decrease and increase it.
The input holds the role, the name, the value and the range, so the buttons are a convenience and not tab stops.
Live example
0 to 10
Usage
labelnames the input and is always visible.min,maxandstepset the range, and the range is said before the user errs (0 to 10) and linked witharia-describedby.valueTextsays the value in words on every change (3 in cart) througharia-valuetext. Never setaria-valuenow,aria-valueminoraria-valuemax:aria-valuenowoverrides the real value, 3 shown and 7 announced.- The value stays as typed. Out of range or empty it is invalid:
aria-invalid="true"and an error withrole="alert", rendered only while invalid, that says the fix ("Must be between 0 and 10"). An empty field is never turned into 0. Only the buttons and Home / End clamp. - At
minormaxthe button that would go past it isdisabled, dashed and muted. If a button disables itself under a click, focus moves to the input. - The buttons are 44 × 44,
type="button",tabindex="-1", witharia-controlspointing at the input and a name by action ("Decrease quantity"). The icon isaria-hidden. - Focus is a 2px gap and a 3px
accentring on the input. Invalid is a 3pxdestructiveedge plus an icon and text, never colour alone.
Accessibility
Keyboard interaction
- Tab lands on the input and leaves it: the buttons are not tab stops. Tab commits the value.
- ArrowUp and ArrowDown change the value by
step. They are native, so they work in every browser and with a swipe on mobile. - Home and End set the minimum and the maximum, and Cmd + Left and Cmd + Right do the same on Mac keyboards without them. They are not native: the component adds them.
- Typing 99 with
max="10"leaves 99 and ArrowUp does not clamp it. The value is validated on change.
Screen reader
- The input announces its own value (
aria-valuetext) when it has focus. WebKit exposes a plain number input as a textbox, so the explicitrole="spinbutton"stays. - A button press leaves focus on the button, so the input does not speak. The new value is announced with
ariaNotify(), once, from the pressed button: "Increase quantity, 5 in cart". WhereariaNotifyis missing nothing is said and nothing breaks. - At a limit focus moves to the input, which says its own value, so nothing is announced.
- The calls are tested, not the speech: nothing here was heard in a screen reader yet.
Related
References
This section is still in progress.