Browse Components

Number

Precise numeric entry with increment and decrement controls.

Basic

Type a quantity or use the controls. Values range from 0 to 20.

View Code
HTML
<div class="field">
  <label for="quantity">
    Quantity
  </label>
  <div class="number" data-number>
    <button
      class="number-step"
      type="button"
      data-number-step="-1"
      aria-label="Decrease Quantity"
      aria-controls="quantity"
      hidden
    >
      <svg
        aria-hidden="true"
        focusable="false"
        xmlns="http://www.w3.org/2000/svg"
        viewbox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="1.75"
        stroke-linecap="round"
        stroke-linejoin="round"
      >
        <path d="M5 12h14">
        </path>
      </svg>
    </button>
    <input
      class="input"
      id="quantity"
      name="quantity"
      type="number"
      min="0"
      max="20"
      step="1"
      value="1"
      inputmode="decimal"
    >
    <button
      class="number-step"
      type="button"
      data-number-step="1"
      aria-label="Increase Quantity"
      aria-controls="quantity"
      hidden
    >
      <svg
        aria-hidden="true"
        focusable="false"
        xmlns="http://www.w3.org/2000/svg"
        viewbox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="1.75"
        stroke-linecap="round"
        stroke-linejoin="round"
      >
        <path d="M12 5v14M5 12h14">
        </path>
      </svg>
    </button>
  </div>
</div>

Decimal steps

Adjust in increments of 0.25, including negative values.

View Code
HTML
<div class="field">
  <label for="decimal-number">
    Quantity
  </label>
  <div class="number" data-number>
    <button
      class="number-step"
      type="button"
      data-number-step="-1"
      aria-label="Decrease Quantity"
      aria-controls="decimal-number"
      hidden
    >
      <svg
        aria-hidden="true"
        focusable="false"
        xmlns="http://www.w3.org/2000/svg"
        viewbox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="1.75"
        stroke-linecap="round"
        stroke-linejoin="round"
      >
        <path d="M5 12h14">
        </path>
      </svg>
    </button>
    <input
      class="input"
      id="decimal-number"
      name="decimal-number"
      type="number"
      min="-5"
      max="5"
      step="0.25"
      value="1.5"
      inputmode="decimal"
    >
    <button
      class="number-step"
      type="button"
      data-number-step="1"
      aria-label="Increase Quantity"
      aria-controls="decimal-number"
      hidden
    >
      <svg
        aria-hidden="true"
        focusable="false"
        xmlns="http://www.w3.org/2000/svg"
        viewbox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="1.75"
        stroke-linecap="round"
        stroke-linejoin="round"
      >
        <path d="M12 5v14M5 12h14">
        </path>
      </svg>
    </button>
  </div>
</div>

Disabled and read-only

Disabled fields are excluded from submission; read-only values remain available.

View Code
HTML
<div class="stack">
  <div class="field">
    <label for="disabled-number">
      Quantity
    </label>
    <div class="number" data-number>
      <button
        class="number-step"
        type="button"
        data-number-step="-1"
        aria-label="Decrease Quantity"
        aria-controls="disabled-number"
        hidden
      >
        <svg
          aria-hidden="true"
          focusable="false"
          xmlns="http://www.w3.org/2000/svg"
          viewbox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          stroke-width="1.75"
          stroke-linecap="round"
          stroke-linejoin="round"
        >
          <path d="M5 12h14">
          </path>
        </svg>
      </button>
      <input
        class="input"
        id="disabled-number"
        name="disabled-number"
        type="number"
        value="3"
        disabled
        inputmode="decimal"
      >
      <button
        class="number-step"
        type="button"
        data-number-step="1"
        aria-label="Increase Quantity"
        aria-controls="disabled-number"
        hidden
      >
        <svg
          aria-hidden="true"
          focusable="false"
          xmlns="http://www.w3.org/2000/svg"
          viewbox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          stroke-width="1.75"
          stroke-linecap="round"
          stroke-linejoin="round"
        >
          <path d="M12 5v14M5 12h14">
          </path>
        </svg>
      </button>
    </div>
  </div>
  <div class="field">
    <label for="readonly-number">
      Quantity
    </label>
    <div class="number" data-number>
      <button
        class="number-step"
        type="button"
        data-number-step="-1"
        aria-label="Decrease Quantity"
        aria-controls="readonly-number"
        hidden
      >
        <svg
          aria-hidden="true"
          focusable="false"
          xmlns="http://www.w3.org/2000/svg"
          viewbox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          stroke-width="1.75"
          stroke-linecap="round"
          stroke-linejoin="round"
        >
          <path d="M5 12h14">
          </path>
        </svg>
      </button>
      <input
        class="input"
        id="readonly-number"
        name="readonly-number"
        type="number"
        value="5"
        readonly
        inputmode="decimal"
      >
      <button
        class="number-step"
        type="button"
        data-number-step="1"
        aria-label="Increase Quantity"
        aria-controls="readonly-number"
        hidden
      >
        <svg
          aria-hidden="true"
          focusable="false"
          xmlns="http://www.w3.org/2000/svg"
          viewbox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          stroke-width="1.75"
          stroke-linecap="round"
          stroke-linejoin="round"
        >
          <path d="M12 5v14M5 12h14">
          </path>
        </svg>
      </button>
    </div>
  </div>
</div>

Form reset

Native reset restores the initial value and control states.

View Code
HTML
<form class="stack">
  <div class="field">
    <label for="reset-number">
      Quantity
    </label>
    <div class="number" data-number>
      <button
        class="number-step"
        type="button"
        data-number-step="-1"
        aria-label="Decrease Quantity"
        aria-controls="reset-number"
        hidden
      >
        <svg
          aria-hidden="true"
          focusable="false"
          xmlns="http://www.w3.org/2000/svg"
          viewbox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          stroke-width="1.75"
          stroke-linecap="round"
          stroke-linejoin="round"
        >
          <path d="M5 12h14">
          </path>
        </svg>
      </button>
      <input
        class="input"
        id="reset-number"
        name="reset-number"
        type="number"
        min="0"
        max="20"
        value="2"
        inputmode="decimal"
      >
      <button
        class="number-step"
        type="button"
        data-number-step="1"
        aria-label="Increase Quantity"
        aria-controls="reset-number"
        hidden
      >
        <svg
          aria-hidden="true"
          focusable="false"
          xmlns="http://www.w3.org/2000/svg"
          viewbox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          stroke-width="1.75"
          stroke-linecap="round"
          stroke-linejoin="round"
        >
          <path d="M12 5v14M5 12h14">
          </path>
        </svg>
      </button>
    </div>
  </div>
  <div>
    <button type="reset">
      Reset Quantity
    </button>
  </div>
</form>

Right to left

Logical placement follows the reading direction.

View Code
HTML
<div dir="rtl" lang="he">
  <div class="field">
    <label for="rtl-number">
      כמות
    </label>
    <div class="number" data-number>
      <button
        class="number-step"
        type="button"
        data-number-step="-1"
        aria-label="הפחתת כמות"
        aria-controls="rtl-number"
        hidden
      >
        <svg
          aria-hidden="true"
          focusable="false"
          xmlns="http://www.w3.org/2000/svg"
          viewbox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          stroke-width="1.75"
          stroke-linecap="round"
          stroke-linejoin="round"
        >
          <path d="M5 12h14">
          </path>
        </svg>
      </button>
      <input
        class="input"
        id="rtl-number"
        name="rtl-number"
        type="number"
        min="0"
        max="20"
        value="1"
        inputmode="decimal"
      >
      <button
        class="number-step"
        type="button"
        data-number-step="1"
        aria-label="הגדלת כמות"
        aria-controls="rtl-number"
        hidden
      >
        <svg
          aria-hidden="true"
          focusable="false"
          xmlns="http://www.w3.org/2000/svg"
          viewbox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          stroke-width="1.75"
          stroke-linecap="round"
          stroke-linejoin="round"
        >
          <path d="M12 5v14M5 12h14">
          </path>
        </svg>
      </button>
    </div>
  </div>
</div>

Installation

Download these files into the matching paths in your project, or use Create to assemble a kit. Include each dependency once. Do not also load app.css.

Add to your page
<link rel="stylesheet" href="/library/assets/base.css">
<link rel="stylesheet" href="/library/assets/field.css">
<link rel="stylesheet" href="/library/assets/number.css">
<script defer src="/library/assets/number.js"></script>

12,463 bytes CSS including base · 2,027 bytes runtime JavaScript

Usage

Choose meaningful bounds

Set min, max and step on the native number input. Decimal steps preserve native precision. Use step=any for unrestricted typing with disabled step buttons.

Preserve form behavior

Typing, arrow keys, required validation, disabled, readonly, submission and reset use native input behavior. Buttons emit input and change. Use linked help and aria-invalid for application validation. Empty values remain empty until edited or stepped.

Mount and remove

Load number.js to reveal the controls. Call layoutNumber.refresh(root) after inserting markup and destroy(wrapper) before removal. Dispatch input after changing a value programmatically. Without JavaScript, the native number input remains usable.

Building with AI? The AI Manifest has these notes and the full contract. See the AI Guide.