Components

Number input

A numeric field with −/+ stepper buttons. The buttons share borders with the centered input like an input group; they step by step, clamp to min/max, and disable themselves at the bounds.

Anatomy

A .ds-number-input group joins a .ds-number-input__step minus, a centered .ds-number-input__field, and a plus — collapsing the shared borders so it reads as one unit.

Stepper group
<div class="ds-number-input">
  <button class="ds-number-input__step" type="button" aria-label="Decrement" tabindex="-1">−</button>
  <input class="ds-number-input__field" type="number" value="3" aria-label="Quantity">
  <button class="ds-number-input__step" type="button" aria-label="Increment" tabindex="-1">+</button>
</div>

Interactive

The − / + buttons step the value and clamp it to the range (0–10 here), disabling at the bounds. The small inline script below wires this demo (no dependencies).

Clamped 0–10
<div class="ds-number-input" data-number-input data-min="0" data-max="10" data-step="1">
  <button class="ds-number-input__step" type="button" aria-label="Decrement" tabindex="-1" data-number-dec>−</button>
  <input class="ds-number-input__field" type="number" value="0" min="0" max="10" step="1" data-number-field>
  <button class="ds-number-input__step" type="button" aria-label="Increment" tabindex="-1" data-number-inc>+</button>
</div>

States

A button disables at its bound; the whole control can be disabled too.

At min · disabled
<div class="ds-number-input">
  <button class="ds-number-input__step" type="button" aria-label="Decrement" tabindex="-1" disabled>−</button>
  <input class="ds-number-input__field" type="number" value="0">
  <button class="ds-number-input__step" type="button" aria-label="Increment" tabindex="-1">+</button>
</div>

React

The NumberInput steps the value clamped to min/max by step, disabling each button at its bound. Controlled (value) or uncontrolled (defaultValue).

<NumberInput>
import { NumberInput } from "@diametral/design-system/react";

<NumberInput
  defaultValue={1}
  min={0}
  max={10}
  step={1}
  onChange={(value) => setQty(value)}
/>