A tiny, fully-themeable, and dependency-free fluid stepper component — for Svelte 5.
Set orientation="vertical" and the
stepper stacks top-to-bottom. Works well as a sidebar rail or alongside vertically-scrolling
content.
Photo by Steve A Johnson on Unsplash
useAutoPlay drives timed step changes
with a visible fill animation. Pause, resume, and loop are all built in.
Photo by National Gallery of Art on Unsplash
Every visual detail is controlled by CSS custom properties — colors, sizes, radii, spacing. Override a few variables to match your branding needs. Pick one to re-skin this page.
Default
Minimal
Hacker
Warm
Brutalist
Default is the built-in look — no CSS or class needed. Pick another theme to see how it's applied.
<Stepper count={5} {active} onStepClick={(i) => (active = i)} />npm i svelte-pasitoOr tell your agent:
Install svelte-pasito (npm i svelte-pasito). Import the Stepper component, then add a stepper to my Svelte file with 5 steps and click-to-navigate.
<script lang="ts"> import { Stepper } from 'svelte-pasito' let active = $state(0)</script><Stepper count={5} {active} onStepClick={(i) => (active = i)}/><script lang="ts"> import { Stepper, useAutoPlay } from 'svelte-pasito' let active = $state(0) const autoplay = useAutoPlay({ count: () => 5, active: () => active, onStepChange: (i) => (active = i), stepDuration: () => 5000, loop: () => true })</script><Stepper count={5} {active} onStepClick={(i) => (active = i)} filling={autoplay.filling} fillDuration={autoplay.fillDuration}/>| Prop | Type | Description |
|---|---|---|
count | number | Total number of steps |
active | number | Zero-based active step index |
onStepClick | (index: number) => void | Called when a step is clicked |
orientation | "horizontal" | "vertical" | Layout direction. Default: "horizontal" |
maxVisible | number | Max visible steps before windowing kicks in |
transitionDuration | number | Transition duration in ms. Default: 500 |
easing | string | CSS timing function. Default: cubic-bezier(0.215, 0.61, 0.355, 1) |
filling | boolean | Show fill progress on the active step |
fillDuration | number | Fill animation duration in ms. Default: 3000 |
className | string | Extra class on the container, for variable overrides |
| Option | Type | Description |
|---|---|---|
count | () => number | Total number of steps |
active | () => number | Current active step |
onStepChange | (index: number) => void | Called to advance the step |
stepDuration | () => number | Time per step in ms. Default: 3000 |
loop | () => boolean | Loop back to the first step. Default: true |
enabled | () => boolean | Enable/disable autoplay. Default: true |
| Property | Type | Description |
|---|---|---|
playing | boolean | Current playback state (reactive) |
toggle | () => void | Toggle play/pause |
filling | boolean | Pass to Stepper filling prop |
fillDuration | number | Pass to Stepper fillDuration prop |
Override any of these on the container via className.
| Variable | Default | Description |
|---|---|---|
--pill-dot-size | 8px | Diameter of inactive dots |
--pill-active-width | 24px | Width of the active pill |
--pill-gap | 6px | Space between steps |
--pill-bg | rgba(0,0,0,0.12) | Inactive dot color |
--pill-active-bg | rgba(0,0,0,0.8) | Active pill color |
--pill-fill-bg | rgba(255,255,255,0.45) | Autoplay fill bar color |
--pill-container-bg | rgba(0,0,0,0.04) | Container background |
--pill-container-border | rgba(0,0,0,0.06) | Container border color |
--pill-container-radius | 999px | Container border radius |
.my-dark-stepper { --pill-bg: rgba(255, 255, 255, 0.15); --pill-active-bg: rgba(255, 255, 255, 0.9); --pill-fill-bg: rgba(255, 255, 255, 0.3); --pill-container-bg: rgba(255, 255, 255, 0.1); --pill-container-border: rgba(255, 255, 255, 0.12);}Steps use role="tab" with aria-selected and an aria-label per step. The active
step is keyboard-focusable, and all transitions resolve instantly under prefers-reduced-motion.