Spinbutton
A headless, accessible spinbutton with keyboard support, configurable step, and auto-bounded Increment/Decrement.
Features
- Keyboard support
- Controlled or uncontrolled
- Bounded min / max
- Configurable step
- Headless
Installation
npm install @ariaui/spinbutton
Examples
Two playgrounds: a compact base control with Heroicons, and a card-style guest counter that shows how to embed a spinbutton in richer marketing or checkout UI.
Both demos use static defaultValue trees so the generated snippet stays copy-pasteable; wire value / onValueChange when you need controlled state.
Default
Compact increment and decrement controls around a centered value display. Use this version when you need a minimal quantity or counter input with explicit bounds.
No preview output yet.
Anatomy
import * as Spinbutton from "@ariaui/spinbutton";
export default function Example() {
return (
<Spinbutton.Root>
<Spinbutton.Decrement />
<Spinbutton.Input />
<Spinbutton.Increment />
</Spinbutton.Root>
);
}
API Reference
Root
Spinbutton container. Manages the current value, keyboard shortcuts, and provides context to Input, Increment, and Decrement.
| Prop | Type | Default |
|---|---|---|
value | number | — |
defaultValue | number | min (or 0) |
onValueChange | (value: number) => void | — |
min | number | Number.MIN_SAFE_INTEGER |
max | number | Number.MAX_SAFE_INTEGER |
step | number | 1 |
disabled | boolean | false |
getValueText | (value: number) => string | — |
| Attribute | Values |
|---|---|
| role | 'group' |
Input
Value display that exposes the full spinbutton ARIA state. Renders the current value as its text content when no children are provided.
| Attribute | Values |
|---|---|
| role | 'spinbutton' |
| aria-valuenow | current value |
| aria-valuemin | min |
| aria-valuemax | max |
| aria-valuetext | getValueText(value) when provided |
| aria-disabled | true when disabled |
Increment
Button that increases the value by `step`. Automatically disabled when the value is at `max`.
| Attribute | Values |
|---|---|
| aria-label | 'Increment' |
Decrement
Button that decreases the value by `step`. Automatically disabled when the value is at `min`.
| Attribute | Values |
|---|---|
| aria-label | 'Decrement' |
Keyboard
| Shortcut | Action |
|---|---|
| ↑ | Increase the value by `step`. |
| ↓ | Decrease the value by `step`. |
| PageUp | Increase the value by a larger magnitude (`step * 10`). |
| PageDown | Decrease the value by a larger magnitude (`step * 10`). |
| Home | Set the value to `min`. |
| End | Set the value to `max`. |
| Tab | Move focus between Decrement, Input, and Increment. |
Accessibility
Spinbutton follows the WAI-ARIA Spinbutton pattern:
Rootrenders asrole="group"so Decrement, Input, and Increment are announced as a unit. Passaria-labeloraria-labelledbyon Root so screen readers announce what the spinbutton controls.Inputcarries the spinbutton role and exposesaria-valuenow,aria-valuemin,aria-valuemax, and optionallyaria-valuetext(fromgetValueText). It is focusable so arrow-key shortcuts apply.IncrementandDecrementare regular buttons — labelled "Increment" / "Decrement" by default — and auto-disable at the range bounds viadisabled+aria-disabled.- When
disabledis set on Root, every part becomes non-interactive and Input is taken out of the tab order. - Keyboard support is delegated to Root's
onKeyDownhandler, so arrow keys, PageUp/PageDown, and Home/End work regardless of which child inside Root has focus.