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.

Preview

No preview output yet.

live.tsxReady

Anatomy

tsx
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.

PropTypeDefault
value
number
defaultValue
numbermin (or 0)
onValueChange
(value: number) => void
min
numberNumber.MIN_SAFE_INTEGER
max
numberNumber.MAX_SAFE_INTEGER
step
number1
disabled
booleanfalse
getValueText
(value: number) => string
AttributeValues
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.

AttributeValues
role'spinbutton'
aria-valuenowcurrent value
aria-valueminmin
aria-valuemaxmax
aria-valuetextgetValueText(value) when provided
aria-disabledtrue when disabled

Increment

Button that increases the value by `step`. Automatically disabled when the value is at `max`.

AttributeValues
aria-label'Increment'

Decrement

Button that decreases the value by `step`. Automatically disabled when the value is at `min`.

AttributeValues
aria-label'Decrement'

Keyboard

ShortcutAction
Increase the value by `step`.
Decrease the value by `step`.
PageUpIncrease the value by a larger magnitude (`step * 10`).
PageDownDecrease the value by a larger magnitude (`step * 10`).
HomeSet the value to `min`.
EndSet the value to `max`.
TabMove focus between Decrement, Input, and Increment.

Accessibility

Spinbutton follows the WAI-ARIA Spinbutton pattern:

  • Root renders as role="group" so Decrement, Input, and Increment are announced as a unit. Pass aria-label or aria-labelledby on Root so screen readers announce what the spinbutton controls.
  • Input carries the spinbutton role and exposes aria-valuenow, aria-valuemin, aria-valuemax, and optionally aria-valuetext (from getValueText). It is focusable so arrow-key shortcuts apply.
  • Increment and Decrement are regular buttons — labelled "Increment" / "Decrement" by default — and auto-disable at the range bounds via disabled + aria-disabled.
  • When disabled is set on Root, every part becomes non-interactive and Input is taken out of the tab order.
  • Keyboard support is delegated to Root's onKeyDown handler, so arrow keys, PageUp/PageDown, and Home/End work regardless of which child inside Root has focus.
Previous
Slider