---
outline: deep
---

# Input stepper

A stepper control that enhances a native `<input type="number">` with decrement/increment buttons and an animated number track.

**`<l-input-stepper>`** — Progressive Custom Element

## Options

```html
<l-input-stepper>
  <input
    type="number"
    value="1"
  />
</l-input-stepper>
```

### Appearance

Pick a visual style via `appearance`. Each appearance has its own CSS import.

#### Default

Bordered box with inline buttons.

```html
<l-input-stepper>
  <input
    type="number"
    value="1"
  />
</l-input-stepper>
```

```css
@import 'luxen-ui/css/input-stepper/default';
```

#### Rounded

Circular standalone buttons with no container border — Airbnb-style.

```html
<l-input-stepper appearance="rounded">
  <input
    type="number"
    min="1"
    max="10"
    value="1"
  />
</l-input-stepper>
```

```css
@import 'luxen-ui/css/input-stepper/rounded';
```

### Size

Set the `size` attribute: `xs`, `sm`, `md` (default), `lg`, `xl`.

```html
<div class="flex items-center gap-4">
  <l-input-stepper size="xs">
    <input
      type="number"
      value="1"
    />
  </l-input-stepper>

  <l-input-stepper size="sm">
    <input
      type="number"
      value="1"
    />
  </l-input-stepper>

  <l-input-stepper size="md">
    <input
      type="number"
      value="1"
    />
  </l-input-stepper>

  <l-input-stepper size="lg">
    <input
      type="number"
      value="1"
    />
  </l-input-stepper>

  <l-input-stepper size="xl">
    <input
      type="number"
      value="1"
    />
  </l-input-stepper>
</div>
```

### Not defined

Before JS loads (`:not(:defined)`), CSS provides a styled fallback with zero layout shift.

```html
<l-input-stepper>
  <input
    type="number"
    value="1"
  />
</l-input-stepper>
```

The CSS reserves space for the stepper buttons via `padding-inline` and matches the exact dimensions of the hydrated component. Once defined, the custom element replaces the padding with its own buttons.

### Min / Max

Constrain the value range via `min` and `max` on the `<input>`.

```html
<l-input-stepper>
  <input
    type="number"
    min="0"
    max="10"
    value="5"
  />
</l-input-stepper>
```

### Disabled

Native `disabled` attribute on the `<input>`.

```html
<l-input-stepper>
  <input
    type="number"
    value="3"
    disabled
  />
</l-input-stepper>
```

### Roller

Enable the animated number roller overlay with `with-roller`.

```html
<l-input-stepper with-roller>
  <input
    type="number"
    min="0"
    max="99"
    value="5"
  />
</l-input-stepper>
```

## Accessibility

### Criteria

- **Role** — Uses native `<input type="number">` and native `<button>` elements — built-in semantics
- **Accessible name** — The input must have an associated label via `<label>` or `aria-label`
- **Disabled state** — Buttons disabled at min/max bounds; entire stepper disabled via `disabled` on the input
- **Form integration** — Native `<input>` participates in form submission and validation directly

### Rules

- Wrap the stepper with a visible `<label>` or provide `aria-label` on the input element

### Keyboard interactions

- `ArrowUp` — Increments the value (native number input behavior)
- `ArrowDown` — Decrements the value (native number input behavior)
- `Tab` — Moves focus between the decrement button, input, and increment button

## API reference

### Importing

```js
import 'luxen-ui/input-stepper';
```

```css
@import 'luxen-ui/css/input-stepper/default';
/* or */
@import 'luxen-ui/css/input-stepper/rounded';
```

### Attributes & Properties

- **min**: `number | undefined` — Minimum allowed value. Falls back to the input's `min` attribute.
- **max**: `number | undefined` — Maximum allowed value. Falls back to the input's `max` attribute.
- **step**: `number | undefined` — Step increment. Falls back to the input's `step` attribute.
- **size**: `InputStepperSize` (default: `'md'`) — Control size.
- **with-roller**: `boolean` (default: `false`) — Enable the animated number roller overlay.
- **decrement-icon**: `string` (default: `'lucide:minus'`) — Icon name for the decrement button.
- **increment-icon**: `string` (default: `'lucide:plus'`) — Icon name for the increment button.

### Events

- **change** — Fired when the value changes. Bubbles. Properties: `value: number`.

### CSS custom properties

- `--border-color` (default: `--l-color-border`) — Border color of the stepper container (default appearance) and of each button (rounded appearance).
- `--border-radius` (default: `--radius-md`) — Border radius of the stepper container (default appearance).
