Number input

Select numbers with fine and coarse steps, including decimal increments.

Basic example

Choose a number with small or large adjustments. Fine arrows sit next to the value; coarse arrows sit on the outside.

Use the single arrows for one step and the double arrows for ten. You can also type a value directly.

Single arrows: ±1 · Double arrows: ±10 · Range: 0–100

<div class="row">
  <div class="input-field col s12">
    <label for="quantity">Quantity</label>
    <input id="quantity" name="quantity" type="text" data-type="number" data-number-controls data-number-variant="filled" step="1" data-number-large-step="10" value="25" min="0" max="100" aria-describedby="quantity-help">
    <p id="quantity-help">Single arrows: ±1 · Double arrows: ±10 · Range: 0–100</p>
  </div>
</div>

Setup

Start with the kmaterialize CSS and JavaScript from Getting started, then follow the component setup below.

Install the optional imask peer and load Materialize CSS. The arrow controls and styles are implemented in kmaterialize. Initialize NumberInput once, or use M.AutoInit(). This documentation initializes the examples through its shared page setup.

import { NumberInput } from 'kmaterialize';

const input = document.querySelector<HTMLInputElement>('#quantity')!;
const number = NumberInput.init(input, {
  controls: true,
  step: 1,
  largeStep: 10,
});
await number.ready;
number.increment();      // +1
number.decrement(true);  // -10

input.addEventListener('change', () => {
  console.log(number.mask?.typedValue); // numeric value without separators
});

// When removing the view:
// number.destroy();

For the decimal alternative, use { controls: true, step: 0.1, largeStep: 1 }. Wrap each example in input-field col s12 inside a row, as shown above. Labels stay above the arrow controls; the original field without arrows retains its floating label.

Examples and variants

Decimal alternative · 0.1 and 1

For finer adjustments, the same control uses tenths for the single arrows and one for the double arrows. Decimal steps avoid floating-point display artifacts.

Single arrows: ±0.1 · Double arrows: ±1 · Range: 0–10

<div class="row">
  <div class="input-field col s12">
    <label for="decimal-quantity">Amount</label>
    <input id="decimal-quantity" name="amount" type="text" data-type="number" data-number-controls data-number-variant="filled" step="0.1" data-number-large-step="1" value="2.5" min="0" max="10" aria-describedby="decimal-help">
    <p id="decimal-help">Single arrows: ±0.1 · Double arrows: ±1 · Range: 0–10</p>
  </div>
</div>

Filled, outlined, or rounded

Choose the same border treatment as your text fields: filled with an underline, or outlined with a full border and 4px corners. Rounded keeps the original 16px corners. Fine arrows have a lighter tint; coarse arrows have a stronger tint. Both follow the environment color and dark mode.

<div class="row">
  <div class="input-field col s12">
    <label for="number-filled">Filled · underline</label>
    <input id="number-filled" type="text" data-type="number" data-number-controls data-number-variant="filled" step="1" value="25">
  </div>
  <div class="input-field col s12">
    <label for="number-outlined">Outlined · full border</label>
    <input id="number-outlined" type="text" data-type="number" data-number-controls data-number-variant="outlined" step="0.1" data-number-large-step="1" value="2.5">
  </div>
  <div class="input-field col s12">
    <label for="number-rounded">Rounded · original style</label>
    <input id="number-rounded" type="text" data-type="number" data-number-controls data-number-variant="rounded" step="1" value="25">
  </div>
</div>

Limits, disabled, and read-only

Controls stop at min/max and disable at the corresponding limit. Disabled and read-only fields cannot be changed by the arrows. Omit min/max to allow an unrestricted range.

<div class="row">
  <div class="input-field col s12">
    <label for="limited-quantity">At the lower limit</label>
    <input id="limited-quantity" type="text" data-type="number" data-number-controls step="1" min="-10" max="10" value="-10">
  </div>
  <div class="input-field col s12">
    <label for="disabled-quantity">Disabled</label>
    <input id="disabled-quantity" type="text" data-type="number" data-number-controls step="1" value="8" disabled>
  </div>
  <div class="input-field col s12">
    <label for="readonly-quantity">Read-only</label>
    <input id="readonly-quantity" type="text" data-type="number" data-number-controls step="1" value="12" readonly>
  </div>
</div>

Existing formatted input

The original masked field remains available without arrow controls. Formatting, thousands separators, and decimal precision still come from the library’s NumberInput component.

<div class="row">
  <div class="input-field col s12">
    <input id="formatted-number" type="text" data-type="number" step="0.01" min="0" max="10000" value="1234.56" placeholder=" ">
    <label for="formatted-number">Formatted amount</label>
  </div>
</div>

Validation

Native type="number" supports min, max, and step validation. For enhanced masked fields, validate the numeric NumberInput value against your rules; their native control is type="text".

These previews keep their error state visible. In your form, show errors after checking a field or submitting, then clear them when the value is valid.

For text fields, use .input-field.error, aria-invalid="true", and a message linked with aria-describedby. Remove the error state when resolved. Use aria-live="polite" for messages updated dynamically.

Required masked value
Enter a quantity.
Outside the allowed range
Choose a quantity from 1 to 10.
<div class="input-field outlined error">
    <i class="material-icons suffix" aria-hidden="true">error</i>
    <input id="validation-quantity" type="text" data-type="number" required placeholder=" " value="" aria-invalid="true" aria-describedby="validation-quantity-error">
    <label for="validation-quantity">Quantity</label>
    <span id="validation-quantity-error" class="supporting-text">Enter a quantity.</span>
</div>

<div class="input-field error">
    <i class="material-icons suffix" aria-hidden="true">error</i>
    <input id="validation-maximum" type="number" min="1" max="10" step="1" placeholder=" " value="12" aria-invalid="true" aria-describedby="validation-maximum-error">
    <label for="validation-maximum">Number of items</label>
    <span id="validation-maximum-error" class="supporting-text">Choose a quantity from 1 to 10.</span>
</div>

Reference

Options and methods

Option / attributeDefault and behavior
controls / data-number-controlsOff by default. Add the attribute, or set controls: true, to enable the four arrows. data-number-controls="false" keeps them off.
data-number-variantrounded (default), outlined, or filled. Sets the border appearance; arrow colors inherit from the Material theme.
step / step1. The small increment; must be positive. Options take precedence over attributes.
largeStep / data-number-large-stepTen times step. The large increment; must be positive.
min / min, max / maxNo limit by default. Arrow changes clamp to the bounds.
scaleWith controls, decimal places are inferred from both increments unless explicitly supplied.
thousandsSeparator / radix / mapToRadixSpace / dot / comma. Existing IMask formatting options.
disabled / readonlyNative attributes disable adjustment. Disabled fieldsets are respected too.

increment(large?) and decrement(large?) adjust by one fine or coarse step after ready. Each adjustment emits bubbling input and change events. Use mask.typedValue when your application needs a number rather than formatted text. destroy() removes the controls, mask, and listeners and restores the original accessibility attributes.

Keyboard and accessibility

Focus the number field and use Up/Down for the fine step, or Page Up/Page Down and Shift+Up/Down for the coarse step. Left/Right remain available for moving the text cursor. Each arrow is a native button with its increment in its accessible name; Enter and Space activate it. The input exposes its current value and limits as a spinbutton.

Colors inherit the surrounding Material theme and dark mode. The controls work without icon fonts, and do not require animation.