Skip to content
Template Empire
Browse components

Input Quantity Stepper

A labeled native number field with deliberate one-press stepping.

Customise

1
8
1
2

Code

<InputQuantityStepper />

Input Quantity Stepper pairs a native number input with explicit decrement and increment buttons for quantities in commerce, booking and other forms. It has no currency, pricing or domain-specific assumptions.

The native input remains the value and keyboard authority. The stepper supports controlled and uncontrolled use, snaps values to a step anchored at min, clamps to the inclusive bounds and disables buttons when the current value reaches a bound. If max is off the step grid, the last reachable grid value is used. Each button press makes one change; holding a button does not repeat.

Invalid min uses zero, invalid max uses at least min (or 99), and an invalid or non-positive step uses one. Non-finite values resolve to min. A valid range where max is below min collapses to min.

Install

Add the @te registry to your components.json once:

{
  "registries": {
    "@te": "https://templateempire.io/r/{name}.json"
  }
}

Then install the component:

npx shadcn@latest add @te/input-quantity-stepper

Usage

import { useState } from "react";
import { InputQuantityStepper } from "@/components/input-quantity-stepper";

export function BookingGuests() {
  const [guests, setGuests] = useState(2);
  return <InputQuantityStepper label="Guests" min={1} max={8} value={guests} onValueChange={setGuests} name="guests" />;
}

Props

PropTypeDefaultDescription
labelstringrequiredVisible label for the native numeric field; blank text falls back to Quantity.
idstringuseId()Optional page-unique input id.
descriptionstringundefinedVisible help text associated with the input.
minnumber0Inclusive lower bound; non-finite values use zero.
maxnumber99Inclusive upper bound; invalid values resolve to at least min. If it is off the step grid, the last reachable grid value is used.
stepnumber1Positive increment anchored at min; invalid values use one.
valuenumberundefinedControlled value. Selects controlled mode at mount.
defaultValuenumberminInitial value for uncontrolled use.
onValueChange(value: number) => voidundefinedCalled once when a user edit or button press changes the normalized value.
namestringundefinedNative form field name.
disabledbooleanfalseDisables the input and both buttons.
classNamestringundefinedAdditional classes merged onto the wrapper.

Customisation

The input and buttons use semantic foreground, background, muted, border and focus tokens. The consumer owns surrounding form layout and quantity meaning.

.booking-quantity { max-inline-size: 20rem; }

Frequently asked questions

Does holding a button repeat the quantity change?
No. Each activation produces a single step, including a sustained pointer press.
Does the component format prices or units?
No. It manages a plain number; include unit context in the label or description and format other business values in your form.

Related components

Build a complete booking formExplore form components for the rest of your flow.Form components