The Stepper component is a number field with a minus and a plus button on either side. Use it for quantities, counts and small amounts, where clicking is faster than typing. For a wide range of values where the exact number matters less, use the Range component instead.
Example
Import the component and bind a number. The buttons step the value, and the field can still be typed into.
<script>
import { Stepper } from "theui-svelte";
let quantity = $state(1)
</script>
<Stepper bind:value={quantity}>Quantity</Stepper>Limits
Set min and max to fence the value in. The matching button turns itself off at each end, and a number typed outside the range is pulled back when the field loses focus.
<Stepper value={1} min={1} max={5} helperText="Between 1 and 5">Tickets</Stepper>Decimal Steps
The step prop can be a fraction. The component keeps the result clean, so half steps give 1.5 rather than 1.5000000000000002.
<script>
let weight = $state(0.5)
</script>
<Stepper bind:value={weight} min={0} max={5} step={0.5}>Weight (kg)</Stepper>Sizes and Variants
The size prop takes sm, md, lg and xl, and variant takes bordered or flat. Both are inherited from a Form or a Fieldset.
<Stepper value={2} size="sm" />
<Stepper value={2} size="md" />
<Stepper value={2} size="lg" />
<Stepper value={2} variant="flat" />Disabled and Read Only
A disabled stepper is switched off completely. A readonly one shows its value but cannot be changed, and still submits with the form.
<Stepper value={2} disabled>Disabled</Stepper>
<Stepper value={2} readonly>Read only</Stepper>In a Form
Give the field a name to submit it, and use onchange to react to every change, such as updating a price.
<form method="POST">
<Stepper name="quantity" bind:value={quantity} min={1} max={10} onchange={(v) => console.log(v)}>
Quantity
</Stepper>
<button>Add to cart</button>
</form>Animation Speed
The animationSpeed prop sets how quickly the field reacts to focus and hover. It takes "none", "slower", "slow", "normal", "fast" and "faster", and the default is "normal". Inside a Form or a Fieldset the value is inherited, so one setting covers every field at once.
<Stepper animationSpeed="slower">Slower</Stepper>
<Stepper animationSpeed="faster">Faster</Stepper>
<Stepper animationSpeed="none">No animation</Stepper>Reset Styles
Set reset to true to drop the border, background and focus ring of the number field and keep only the classes you pass. The two buttons keep their own styling, which buttonClasses replaces. The default is false, and a Form or a Fieldset can set it for every field it holds.
<Stepper
reset
class="w-20 border-0 border-b-2 border-gray-400 text-center"
buttonClasses="border-0 bg-transparent text-xl">
Underline only
</Stepper>Customization
Use buttonClasses for the minus and plus buttons, class for the field itself and wrapperClasses for everything together. The button labels can be reworded with decreaseLabel and increaseLabel.
<Stepper
value={2}
rounded="full"
buttonClasses="rounded-full bg-brand-500 text-on-brand border-transparent"
class="w-24"
/>
<Stepper value={2} decreaseLabel="One fewer" increaseLabel="One more" />Accessibility
The field is a native number input, so screen readers announce it as a spin button with its value and limits, and the arrow keys step it. The two buttons have their own names, set with decreaseLabel and increaseLabel, and point at the field with aria-controls. They are real buttons of type button, so they never submit the form around them. Holding one down keeps stepping after a short pause, which saves many clicks without making a single click hard to aim.