Input stepper <l-input-stepper>
A stepper control that enhances a native <input type="number"> with decrement/increment buttons and an animated number track.
<l-input-stepper>Options
Appearance
Pick a visual style via appearance. Each appearance has its own CSS import.
Default
Bordered box with inline buttons.
@import 'luxen-ui/css/input-stepper/default';<l-input-stepper>
<input
type="number"
value="1"
/>
</l-input-stepper>Rounded
Circular standalone buttons with no container border — Airbnb-style.
@import 'luxen-ui/css/input-stepper/rounded';<l-input-stepper appearance="rounded">
<input
type="number"
min="1"
max="10"
value="1"
/>
</l-input-stepper>Pill
Circular buttons inset into a filled capsule track — iOS-style quantity picker.
@import 'luxen-ui/css/input-stepper/pill';<l-input-stepper appearance="pill">
<input
type="number"
min="1"
max="10"
value="5"
/>
</l-input-stepper>Size
Set the size attribute: xs, sm, md (default), lg, xl. All three appearances scale from the same control-height tokens, so their buttons match a button or input of the same size. pill then adds its inset around that row, which makes the capsule itself 8px taller than the other two at every size — give it its own line rather than a shared one when you put it in a row of form controls.
Code
<div class="flex flex-wrap gap-6 items-start">
<div class="flex flex-col gap-4 items-start">
<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>
<div class="flex flex-col gap-4 items-start">
<l-input-stepper
appearance="rounded"
size="xs"
>
<input
type="number"
value="1"
/>
</l-input-stepper>
<l-input-stepper
appearance="rounded"
size="sm"
>
<input
type="number"
value="1"
/>
</l-input-stepper>
<l-input-stepper
appearance="rounded"
size="md"
>
<input
type="number"
value="1"
/>
</l-input-stepper>
<l-input-stepper
appearance="rounded"
size="lg"
>
<input
type="number"
value="1"
/>
</l-input-stepper>
<l-input-stepper
appearance="rounded"
size="xl"
>
<input
type="number"
value="1"
/>
</l-input-stepper>
</div>
<div class="flex flex-col gap-4 items-start">
<l-input-stepper
appearance="pill"
size="xs"
>
<input
type="number"
value="1"
/>
</l-input-stepper>
<l-input-stepper
appearance="pill"
size="sm"
>
<input
type="number"
value="1"
/>
</l-input-stepper>
<l-input-stepper
appearance="pill"
size="md"
>
<input
type="number"
value="1"
/>
</l-input-stepper>
<l-input-stepper
appearance="pill"
size="lg"
>
<input
type="number"
value="1"
/>
</l-input-stepper>
<l-input-stepper
appearance="pill"
size="xl"
>
<input
type="number"
value="1"
/>
</l-input-stepper>
</div>
</div>Not defined
Before JS loads (:not(:defined)), CSS provides a styled fallback with zero layout shift.
Code
<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>.
Code
<l-input-stepper>
<input
type="number"
min="0"
max="10"
value="5"
/>
</l-input-stepper>Disabled
Native disabled attribute on the <input>.
Code
<div class="flex flex-wrap items-center gap-4">
<l-input-stepper>
<input
type="number"
value="3"
disabled
/>
</l-input-stepper>
<l-input-stepper appearance="rounded">
<input
type="number"
value="3"
disabled
/>
</l-input-stepper>
<l-input-stepper appearance="pill">
<input
type="number"
value="3"
disabled
/>
</l-input-stepper>
</div>Roller
Enable the animated number roller overlay with with-roller.
Code
<div class="flex flex-wrap items-center gap-4">
<l-input-stepper with-roller>
<input
type="number"
min="0"
max="99"
value="5"
/>
</l-input-stepper>
<l-input-stepper
appearance="rounded"
with-roller
>
<input
type="number"
min="0"
max="99"
value="5"
/>
</l-input-stepper>
<l-input-stepper
appearance="pill"
with-roller
>
<input
type="number"
min="0"
max="99"
value="5"
/>
</l-input-stepper>
</div>Accessibility
Criteria
- Role
Uses native
<input type="number">and native<button>elements — built-in semanticsWCAG4.1.2RGAA11.1- Disabled state
Buttons disabled at min/max bounds; entire stepper disabled via
disabledon the inputWCAG4.1.2- Form integration
Native
<input>participates in form submission and validation directlyWCAG4.1.2
Rules
- Wrap the stepper with a visible
<label>or providearia-labelon the input element
Keyboard interactions
API reference
Importing
import 'luxen-ui/input-stepper';@import 'luxen-ui/css/input-stepper/default';
/* or */
@import 'luxen-ui/css/input-stepper/rounded';
/* or */
@import 'luxen-ui/css/input-stepper/pill';Attributes & Properties
minnumber | undefinedProperty- Minimum allowed value. Falls back to the input's
minattribute. maxnumber | undefinedProperty- Maximum allowed value. Falls back to the input's
maxattribute. stepnumber | undefinedProperty- Step increment. Falls back to the input's
stepattribute. sizeInputStepperSizedefault:'md'Property- Control size.
with-rollerbooleandefault:falseProperty- Enable the animated number roller overlay.
decrement-iconstringdefault:'lucide:minus'Property- Icon name for the decrement button.
increment-iconstringdefault:'lucide:plus'Property- Icon name for the increment button.
Events
changeEvent- Fired when the value changes. Bubbles. Properties:
value: number.
CSS custom properties
--border-colordefault:--l-color-borderCustom property- Edge color of the stepper container (default and pill appearances) and of each button (rounded appearance).
--border-radiusdefault:--radius-mdCustom property- Border radius of the stepper container (default appearance).