Stepper
A fully interactive, accessible, user interface component that allows users to increment or decrement a value. It is commonly used for inputting numerical values, such as quantities or prices.
import { Stepper, StepperButton, StepperInput, StepperLabel,} from "@/registry/ui/stepper"
export default function StepperDemo() { return ( <Stepper start={0}> <StepperLabel htmlFor="stepper">Quantity</StepperLabel> <StepperButton direction="down">-</StepperButton> <StepperInput id="stepper" /> <StepperButton direction="up">+</StepperButton> </Stepper> )}Installation#
You can install this component via the shadcn CLI.
npx shadcn@latest add https://jakeisonline.com/registry/stepper.jsonUsage#
import { Stepper, StepperButton, StepperInput, StepperLabel,} from "@/components/ui/stepper"<Stepper start={0}> <StepperLabel htmlFor="stepper">Quantity</StepperLabel> <StepperButton direction="down">-</StepperButton> <StepperInput id="stepper" /> <StepperButton direction="up">+</StepperButton></Stepper>Accessibility#
Adheres to the Spinbutton WAI-ARIA design pattern. At its core, this component is simply a native number field.
<StepperInput> requires the property id (string) to be set, and should match the htmlFor (string) of the <StepperLabel>.
Keyboard interactions#
| Key | Action |
|---|---|
| ArrowUp | Increment value by step, or 1 |
| ArrowDown | Decrement value by step, or 1 |
| Shift + ArrowUp | Increment value by shift |
| Shift + ArrowDown | Decrement value by shift |
| PageUp | Increment value by shift |
| PageDown | Decrement value by shift |
| Home | Set value to min |
| End | Set value to max |
Component Reference#
Stepper#
Used to wrap a single stepper field. Also provides context for all child components.
| Prop | Type | Description |
|---|---|---|
start | number | The initial value of the field. Default 0. |
step | number | The step size of the field. Default 1. |
shift | number | The step size of the field when holding Shift or PageUp/PageDown. |
min | number | The minimum value of the field. |
max | number | The maximum value of the field. |
StepperLabel#
The <label> of the stepper field.
| Prop | Type | Description |
|---|---|---|
htmlFor | string | Should match the id of the StepperInput. |
StepperButton#
The controller <button> of a stepper field, which users can interact with to step the value up or down.
| Prop | Type | Description |
|---|---|---|
direction | string | up or down depending on desired direction. Required. |
StepperInput#
The <input> of the stepper field.
| Prop | Type | Description |
|---|---|---|
id | string | Should match the htmlFor of the StepperLabel. |
StepperBadge#
An optional floating badge that displays the current value of the field.
| Prop | Type | Description |
|---|---|---|
hideWhen | number | Automatically hides the badge when the value is equal to this number. Defaults to 0. |
Examples#
Allow shift stepping#
Shift stepping allowing users to increment or decrement a value by a larger amount. When shift is set, users can shift step by holding Shift while clicking a <StepperButton>, or by using the keyboard interactions.
import { Stepper, StepperButton, StepperInput, StepperLabel,} from "@/registry/ui/stepper"
export default function StepperShift() { return ( <Stepper min={0} shift={10} max={100}> <StepperLabel htmlFor="shift">Quantity</StepperLabel> <StepperButton direction="down">-</StepperButton> <StepperInput id="shift" /> <StepperButton direction="up">+</StepperButton> </Stepper> )}Collapsing stepper fields#
You might want to display multiple quantities in a single row. For example, when ordering multiple product variants in bulk, or providing measurements for a product.
import { Stepper, StepperButton, StepperInput, StepperLabel, StepperBadge,} from "@/registry/ui/stepper"
export default function StepperCollapse() { return ( <div className="flex gap-3"> <Stepper min={0} start={0} shift={10} className="min-w-8"> <StepperLabel htmlFor="small" className="mr-0 border-r-0 group-has-[:focus]:border-r" > S </StepperLabel> <div className="flex w-0 flex-row items-center gap-1 overflow-hidden opacity-0 has-[:focus]:w-full has-[:focus]:overflow-auto has-[:focus]:opacity-100"> <StepperButton direction="down">-</StepperButton> <StepperInput id="small" /> <StepperButton direction="up">+</StepperButton> </div> <StepperBadge /> </Stepper> <Stepper min={0} start={3} shift={10} className="min-w-8"> <StepperLabel htmlFor="medium" className="mr-0 border-r-0 group-has-[:focus]:border-r" > M </StepperLabel> <div className="flex w-0 flex-row items-center gap-1 overflow-hidden opacity-0 has-[:focus]:w-full has-[:focus]:overflow-auto has-[:focus]:opacity-100"> <StepperButton direction="down">-</StepperButton> <StepperInput id="medium" /> <StepperButton direction="up">+</StepperButton> </div> <StepperBadge /> </Stepper> <Stepper min={0} start={0} shift={10} className="min-w-8"> <StepperLabel htmlFor="large" className="mr-0 border-r-0 group-has-[:focus]:border-r" > L </StepperLabel> <div className="flex w-0 flex-row items-center gap-1 overflow-hidden opacity-0 has-[:focus]:w-full has-[:focus]:overflow-auto has-[:focus]:opacity-100"> <StepperButton direction="down">-</StepperButton> <StepperInput id="large" /> <StepperButton direction="up">+</StepperButton> </div> <StepperBadge /> </Stepper> </div> )}