Pasito

A tiny, fully-themeable, and dependency-free fluid stepper component — for Svelte 5.

Vertical

Set orientation="vertical" and the stepper stacks top-to-bottom. Works well as a sidebar rail or alongside vertically-scrolling content.

yellow, red, green, and black abstract painting

Photo by Steve A Johnson on Unsplash

Autoplay

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

Themes

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

Using Default

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)} />

Installation

Original
npm i svelte-pasito

Or 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.

Usage

<script lang="ts">
import { Stepper } from 'svelte-pasito'
let active = $state(0)
</script>
<Stepper
count={5}
{active}
onStepClick={(i) => (active = i)}
/>

Autoplay Usage

<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}
onfocusin={autoplay.handleFocusIn}
onfocusout={autoplay.handleFocusOut}
/>

API Reference

<Stepper />

PropTypeDescription
countnumberTotal number of steps
activenumberZero-based active step index
onStepClick(index: number) => voidCalled when a step is clicked
orientation"horizontal" | "vertical"Layout direction. Default: "horizontal"
maxVisiblenumberMax visible steps before windowing kicks in
transitionDurationnumberTransition duration in ms. Default: 500
easingstringCSS timing function. Default: cubic-bezier(0.215, 0.61, 0.355, 1)
fillingbooleanShow fill progress on the active step
fillDurationnumberFill animation duration in ms. Default: 3000
classNamestringExtra class on the container, for variable overrides
onfocusin(event: FocusEvent) => voidFocus entered the stepper. Pass autoplay.handleFocusIn
onfocusout(event: FocusEvent) => voidFocus left a step. Pass autoplay.handleFocusOut

useAutoPlay(options)

OptionTypeDescription
count() => numberTotal number of steps
active() => numberCurrent active step
onStepChange(index: number) => voidCalled to advance the step
stepDuration() => numberTime per step in ms. Default: 3000
loop() => booleanLoop back to the first step. Default: true
enabled() => booleanEnable/disable autoplay. Default: true

Returns

PropertyTypeDescription
playingbooleanCurrent playback state (reactive)
toggle() => voidToggle play/pause
fillingbooleanPass to Stepper filling prop
fillDurationnumberPass to Stepper fillDuration prop
handleFocusIn() => voidPass to Stepper onfocusin: pauses while focused
handleFocusOut(event?: FocusEvent) => voidPass to Stepper onfocusout: resumes if it paused

Theming

Override any of these on the container via className.

VariableDefaultDescription
--pill-dot-size8pxDiameter of inactive dots
--pill-active-width24pxWidth of the active pill
--pill-gap6pxSpace between steps
--pill-bgrgba(0,0,0,0.12)Inactive dot color
--pill-active-bgrgba(0,0,0,0.8)Active pill color
--pill-fill-bgrgba(255,255,255,0.45)Autoplay fill bar color
--pill-container-bgrgba(0,0,0,0.04)Container background
--pill-container-borderrgba(0,0,0,0.06)Container border color
--pill-container-radius999pxContainer border radius

Dark theme

.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);
}

Accessibility

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.

Keyboard

Arrow keys work whenever onStepClick is passed.

KeyOrientationAction
← →HorizontalPrevious / next step (wraps around)
↑ ↓VerticalPrevious / next step (wraps around)
Home / EndBothFirst / last step
Enter / SpaceBothSelect the focused step
TabBothMove into and out of the stepper (lands on the active step)

Autoplay

Wire onfocusin and onfocusout to the autoplay handlers (see Autoplay Usage) and playback pauses while focus is inside the stepper, then resumes when it leaves — but only if it was playing before. Your play/pause button is a normal button, so Space toggles it.

Changelog

0.2.0 2026-10-10

Added

  • Keyboard navigation: ← → (or ↑ ↓ when vertical) move between steps and wrap around, Home / End jump to the first / last step. Focus follows the selected step.
  • onfocusin and onfocusout props on Stepper.
  • handleFocusIn and handleFocusOut on useAutoPlay / AutoPlayController: wire them to the stepper so autoplay pauses while keyboard focus is inside it and resumes when focus leaves (only if it was playing before).

Changed

  • Steps that are animating out can no longer be reached with the arrow keys.

0.1.1 2026-09-24

Changed

  • README and package homepage link to the live demo.

0.1.0 2026-09-23

Added

  • Initial release: Svelte 5 port of pasito by Josh Puckett.
  • Stepper component with horizontal and vertical orientation, windowing via maxVisible, and animated step add/remove.
  • useAutoPlay and AutoPlayController for timed step changes with a fill animation.
  • Theming through --pill-* CSS custom properties.