data-stepper

Add custom increment and decrement buttons to number inputs. Respects min, max, and step attributes with automatic button disabling at boundaries.

Overview

The data-stepper attribute enhances a native <input type="number"> with visible increment and decrement buttons. Just add the attribute — the script reads min, max, and step from the input and builds the controls automatically.

How It Works

Add data-stepper to any <input type="number">. The init script:

  1. Wraps the input in a .number-wrapper container
  2. Inserts a decrease button (with aria-label="Decrease") before the input
  3. Inserts an increase button (with aria-label="Increase") after the input
  4. Sets both buttons to tabindex="-1" so the input itself keeps keyboard focus
  5. Reads min, max, and step attributes for boundary logic
  6. Disables the decrease button when at min, the increase button when at max
  7. Sets data-stepper-init to prevent double-binding

The underlying input remains a real form control. It submits with the form, supports validation, and native keyboard arrows still increment and decrement as expected.

Attributes

Attribute Values Description
data-stepper boolean Enables the stepper enhancement on a number input.
data-stepper-init boolean Set automatically to prevent double-binding. Do not set manually.
min number Standard HTML attribute. The decrease button is disabled at this value.
max number Standard HTML attribute. The increase button is disabled at this value.
step number Standard HTML attribute. Controls the increment/decrement amount per click.

Decimal Steps

When step is a decimal value, the stepper uses toFixed() to maintain precision. No floating-point drift — values stay clean.

Custom Ranges

Combine min, max, and step for any numeric range. Buttons disable automatically at boundaries.

No Min/Max

Without min or max, neither button ever disables. The stepper allows unbounded incrementing and decrementing.

Button State at Boundaries

The stepper automatically manages button states based on the current value:

  • When the value equals min, the decrease button gets disabled
  • When the value equals max, the increase button gets disabled
  • Button states update on every step, keyboard change, and manual input
  • Disabled buttons use reduced opacity and cursor: not-allowed

Events

Clicking a stepper button fires both input and change events on the underlying input, matching the behavior of native keyboard arrows.

Event Target Description
input The <input> Fired immediately when a stepper button is clicked.
change The <input> Fired after the value changes, matching native behavior.

In a Form

Steppers work naturally inside forms. Combine multiple steppers for booking or quantity selection interfaces.

Styling

The .number-wrapper container and its buttons are styled via CSS. All styles are gated on [data-stepper-init] so the input renders normally without JavaScript.

The wrapper uses inline-flex for alignment and rounds the outer corners. Button disabled states reduce opacity for clear visual feedback.

Dynamic Elements

Inputs added to the DOM after page load are automatically enhanced via a MutationObserver. No manual initialization is needed.