v1.1.1

Number Input

A numeric input with increment and decrement buttons for precise value control.

Interactive Requires: veritheme.js JS init: automatic

Default

Basic number input with +/- buttons.

html
<div class="vt-number-input vt-bg-surface-card" data-number-input="">
  <button type="button" class="vt-number-input-btn" data-action="decrement">
    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-minus vt-w-4 vt-h-4">
      <path d="M5 12h14"></path>
    </svg>
  </button>
  <input type="number" value="1" min="0" max="99" class="vt-number-input-value vt-bg-transparent vt-outline-none vt-tabular-nums" data-number-value="" aria-label="Value">
  <button type="button" class="vt-number-input-btn" data-action="increment">
    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-plus vt-w-4 vt-h-4">
      <path d="M5 12h14"></path><path d="M12 5v14"></path>
    </svg>
  </button>
</div>

With Label

Number input paired with a label and helper text.

html

Select between 1 and 99

<div class="vt-space-y-2">
  <label class="vt-text-sm vt-font-medium vt-block" for="number-input-2-1">Quantity</label>
  <div class="vt-number-input vt-bg-surface-card" data-number-input="">
    <button type="button" class="vt-number-input-btn" data-action="decrement">
      <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-minus vt-w-4 vt-h-4">
        <path d="M5 12h14"></path>
      </svg>
    </button>
    <input type="number" value="3" min="1" max="99" class="vt-number-input-value vt-bg-transparent vt-outline-none vt-tabular-nums" data-number-value="" id="number-input-2-1" aria-describedby="number-input-2-2">
    <button type="button" class="vt-number-input-btn" data-action="increment">
      <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-plus vt-w-4 vt-h-4">
        <path d="M5 12h14"></path><path d="M12 5v14"></path>
      </svg>
    </button>
  </div>
  <p class="vt-text-xs vt-text-foreground-muted" id="number-input-2-2">Select between 1 and 99</p>
</div>

Sizes

Small, medium, and large number input variants.

html
<div class="vt-number-input vt-number-input-sm vt-bg-surface-card" data-number-input="">
  <button type="button" class="vt-number-input-btn" data-action="decrement">
    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-minus vt-w-3 vt-h-3">
      <path d="M5 12h14"></path>
    </svg>
  </button>
  <input type="number" value="2" min="0" max="99" class="vt-number-input-value vt-bg-transparent vt-outline-none vt-tabular-nums" data-number-value="" aria-label="Value">
  <button type="button" class="vt-number-input-btn" data-action="increment">
    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-plus vt-w-3 vt-h-3">
      <path d="M5 12h14"></path><path d="M12 5v14"></path>
    </svg>
  </button>
</div>

<div class="vt-number-input vt-bg-surface-card" data-number-input="">
  <button type="button" class="vt-number-input-btn" data-action="decrement">
    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-minus vt-w-4 vt-h-4">
      <path d="M5 12h14"></path>
    </svg>
  </button>
  <input type="number" value="5" min="0" max="99" class="vt-number-input-value vt-bg-transparent vt-outline-none vt-tabular-nums" data-number-value="" aria-label="Value">
  <button type="button" class="vt-number-input-btn" data-action="increment">
    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-plus vt-w-4 vt-h-4">
      <path d="M5 12h14"></path><path d="M12 5v14"></path>
    </svg>
  </button>
</div>

<div class="vt-number-input vt-number-input-lg vt-bg-surface-card" data-number-input="">
  <button type="button" class="vt-number-input-btn" data-action="decrement">
    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-minus vt-w-5 vt-h-5">
      <path d="M5 12h14"></path>
    </svg>
  </button>
  <input type="number" value="8" min="0" max="99" class="vt-number-input-value vt-bg-transparent vt-outline-none vt-tabular-nums" data-number-value="" aria-label="Value">
  <button type="button" class="vt-number-input-btn" data-action="increment">
    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-plus vt-w-5 vt-h-5">
      <path d="M5 12h14"></path><path d="M12 5v14"></path>
    </svg>
  </button>
</div>

Min / Max

Number input with min and max constraints. Buttons disable at boundaries.

html

Min: 1, Max: 10

<div class="vt-space-y-2 vt-text-center">
  <div class="vt-number-input vt-bg-surface-card" data-number-input="">
    <button type="button" class="vt-number-input-btn disabled:vt-opacity-30 disabled:vt-pointer-events-none" data-action="decrement" disabled="">
      <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-minus vt-w-4 vt-h-4">
        <path d="M5 12h14"></path>
      </svg>
    </button>
    <input type="number" value="1" min="1" max="10" class="vt-number-input-value vt-bg-transparent vt-outline-none vt-tabular-nums" data-number-value="" aria-label="Value" aria-describedby="number-input-4-1">
    <button type="button" class="vt-number-input-btn disabled:vt-opacity-30 disabled:vt-pointer-events-none" data-action="increment">
      <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-plus vt-w-4 vt-h-4">
        <path d="M5 12h14"></path><path d="M12 5v14"></path>
      </svg>
    </button>
  </div>
  <p class="vt-text-xs vt-text-foreground-muted" id="number-input-4-1">Min: 1, Max: 10</p>
</div>

Disabled

Disabled state for read-only display.

html
<div class="vt-number-input vt-bg-surface-subtle vt-opacity-50 vt-pointer-events-none">
  <button type="button" class="vt-number-input-btn" disabled="">
    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-minus vt-w-4 vt-h-4">
      <path d="M5 12h14"></path>
    </svg>
  </button>
  <input type="number" value="5" disabled="" class="vt-number-input-value vt-bg-transparent vt-outline-none vt-tabular-nums vt-text-foreground-disabled" aria-label="Value">
  <button type="button" class="vt-number-input-btn" disabled="">
    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-plus vt-w-4 vt-h-4">
      <path d="M5 12h14"></path><path d="M12 5v14"></path>
    </svg>
  </button>
</div>

Shopping Cart Example

Number input in a product card context.

🎧

Wireless Headphones

Premium noise cancelling

$299

Guidelines

Precise numeric values with +/- steppers. Ranges where exact value matters less → slider.

Min: 1, Max: 10

Do
Set min and max so steppers stop at valid bounds.
Don't
Don't omit min and max when only a narrow range is valid.

API Reference

All data attributes and utility classes available for the Number Input component.

Class Type Description
[data-number-input] Container Wrapper element that groups buttons and input together
[data-action="decrement"] Button Decrement button — decreases value by 1
[data-action="increment"] Button Increment button — increases value by 1
[data-number-value] Input The number input field itself
vt-h-8 Size Small size variant (height 32px)
vt-h-10 Size Default size variant (height 40px)
vt-h-12 Size Large size variant (height 48px)
disabled State Disabled state — reduced opacity, pointer events none

Accessibility

Keyboard and screen reader support.

Feature Details
Keyboard Arrow keys work in the input, buttons are keyboard accessible via Tab
Screen Reader Input announces current value and constraints (min/max)
ARIA Use aria-label on increment/decrement buttons for clarity
Min/Max Buttons auto-disable at boundaries, preventing invalid values
Focus Input receives focus ring, buttons show hover/focus states