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.json
Usage#
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> )}