SpinBox — HTML & CSS
A numeric stepper with + / − buttons, hold-to-repeat, min/max clamping, decimal support and a screen-reader-friendly value. Configured entirely through data-* attributes on the markup.
Wiring it up in JS (init, events, API, Vue) is on the JavaScript page.
Live example
Interact with these — type, use the arrows, hold a button, or press Shift while clicking for a bigger step. The readout shows the ui-spinbox-change event the component emits.
Color
Size — sm · default · lg
Shape (no color) — r-0 · default · r-round
Disabled — data-disabled in markup, rendered inert:
Reactive disable — toggling :data-disabled re-inits via destroy() → scan() (the typed value survives):
Last ui-spinbox-change: —
Markup
A SpinBox is a .UIsp container holding two .UIsp__btn buttons around a .UIsp__input. Behavior is configured with data-* attributes:
<div class="UIsp primary" data-min="0" data-max="100"
role="spinbutton" tabindex="0" aria-label="Volume">
<button class="UIsp__btn" type="button" aria-label="Decrease">−</button>
<input class="UIsp__input" id="volume" type="text" value="50"
aria-label="Current value" inputmode="decimal" />
<button class="UIsp__btn" type="button" aria-label="Increase">+</button>
</div>Minimal markup
The smallest working SpinBox — no color, no bounds, no label:
<div class="UIsp" role="spinbutton" tabindex="0" aria-label="Value">
<button class="UIsp__btn" type="button" aria-label="Decrease">−</button>
<input class="UIsp__input" type="text" value="0"
aria-label="Current value" inputmode="decimal" />
<button class="UIsp__btn" type="button" aria-label="Increase">+</button>
</div>Options (data-*)
| Attribute | Meaning |
|---|---|
data-min | Lower bound (default 0). |
data-max | Upper bound. 0 (default) means no upper limit. |
data-decimals | Number of decimal places to display (alias: data-step). |
data-unit | Unit appended to the screen-reader value, e.g. "kg" → 2.5 kg. |
data-negative | Opt in to negative values (positive-only without it). |
data-disabled | Render the control disabled. |