Input Quantity Stepper
A labeled native number field with deliberate one-press stepping.
Customise
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-stepperUsage
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
| Prop | Type | Default | Description |
|---|---|---|---|
| label | string | required | Visible label for the native numeric field; blank text falls back to Quantity. |
| id | string | useId() | Optional page-unique input id. |
| description | string | undefined | Visible help text associated with the input. |
| min | number | 0 | Inclusive lower bound; non-finite values use zero. |
| max | number | 99 | Inclusive upper bound; invalid values resolve to at least min. If it is off the step grid, the last reachable grid value is used. |
| step | number | 1 | Positive increment anchored at min; invalid values use one. |
| value | number | undefined | Controlled value. Selects controlled mode at mount. |
| defaultValue | number | min | Initial value for uncontrolled use. |
| onValueChange | (value: number) => void | undefined | Called once when a user edit or button press changes the normalized value. |
| name | string | undefined | Native form field name. |
| disabled | boolean | false | Disables the input and both buttons. |
| className | string | undefined | Additional 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.