Skip to content

Number Input

A numeric input with increment and decrement buttons. Constrains input to numbers within an optional range.

Preview

Sizes

States

Minimum quantity is 1.

Features

  • Increment/decrement buttons for mouse and touch users.
  • Native <input type="number"> for keyboard support (arrow keys, direct typing).
  • Browser spin buttons hidden — custom buttons provide consistent appearance.
  • Focus ring wraps the entire composite control.

States

StateAppearance
DefaultButtons flanking the number field
FocusBrand-purple border with focus shadow around the entire control
Hover (button)Button background shift
DisabledReduced opacity, no interaction
ErrorRed border with error message

Props

PropTypeDefaultDescription
valuenumber--Current value
onChange(value: number) => void--Change handler
minnumber--Minimum allowed value
maxnumber--Maximum allowed value
stepnumber1Increment step
size'sm' | 'md' | 'lg''md'Input size
disabledbooleanfalseDisables the input
errorstring--Error message
labelstring--Visible label

Code example

React

tsx
import { NumberInput } from '@thepace/lexicon/components';

<NumberInput label="Quantity" value={qty} onChange={setQty}
             min={1} max={99} />

Vanilla HTML

html
<div class="lex-input-wrapper">
  <label class="lex-input__label">Quantity</label>
  <div class="lex-number-input lex-number-input--md">
    <button class="lex-number-input__btn" aria-label="Decrease">−</button>
    <input type="number" class="lex-number-input__field"
           value="3" min="1" max="99" />
    <button class="lex-number-input__btn" aria-label="Increase">+</button>
  </div>
</div>

CSS class reference

ClassPurpose
.lex-number-inputComposite container
.lex-number-input__fieldThe number input
.lex-number-input__btnIncrement/decrement button
.lex-number-input--smSmall size
.lex-number-input--mdMedium size
.lex-number-input--lgLarge size
.lex-number-input--disabledDisabled state
.lex-number-input--errorError state

Accessibility

  • Buttons have aria-label ("Increase" / "Decrease").
  • Native <input type="number"> handles keyboard arrow key increments.
  • When min/max is reached, the corresponding button should be disabled and set aria-disabled="true".
  • Focus ring wraps the entire composite control via :focus-within.

Guidelines

Do

  • Set clear min and max boundaries and communicate them.
  • Disable the decrement button at min and increment at max.

Don't

  • Don't use for free-form numeric entry — use a standard Input with type="number".
  • Don't omit aria-label on the increment/decrement buttons.

Released under the MIT License. A product by the pace.