Navigation

Steps

Ordered progress indicator that visualizes a fixed sequence of steps with completed, current, skipped, and upcoming states.

import { Steps } from '@lostgradient/cinder/steps';
navigationprogress
01

Overview

Horizontal or vertical step indicator for multi-step wizards and onboarding flows.

Usage

svelte
<script lang="ts">
  import { Steps } from '@lostgradient/cinder/steps';
  import type { StepItem } from '@lostgradient/cinder/steps';

  const steps: StepItem[] = [
    { id: 'account', label: 'Account' },
    { id: 'profile', label: 'Profile' },
    { id: 'review', label: 'Review' },
  ];
</script>

<Steps {steps} currentStep={0} label="Onboarding" />

Interactive steps

A step is static text by default. Give a StepItem an href or an onclick and its body (label + description) becomes a focusable control — an <a> for href, a <button> for onclick. The marker circle and the connector line stay decorative, so only the body region is clickable and the marker never joins the accessible name.

svelte
const steps = [
  { id: 'account', label: 'Account', href: '#account' },
  { id: 'profile', label: 'Profile', onclick: () => goToProfile() },
  { id: 'review', label: 'Review' }, // plain, non-interactive
];

When a step has both href and onclick, it renders as a link and still runs the callback on click — the consumer decides whether to preventDefault (for SPA routing interception, analytics, or confirmation). For the current step, aria-current="step" moves onto the interactive element; static steps keep it on the list item.

Skipped steps

By default, state is derived from currentStep: earlier steps are complete, the matching index is current, and later steps are upcoming. Set state: 'skipped' on a StepItem when a flow advances past a step without completing it. Skipped steps keep their numeric marker, use neutral styling, and announce the skippedLabel text instead of the completed label.

svelte
const steps = [
  { id: 'account', label: 'Account' },
  { id: 'profile', label: 'Profile', state: 'skipped' },
  { id: 'review', label: 'Review' },
];
Live preview
02

When to use

Use when
  • Walking the user through a multi-step wizard or checkout flow with strict ordering.
  • Showing how far the user has advanced through a known number of stages.
Avoid when
  • Switching between independent peer views with no order — use tabs instead.
  • Showing ancestor hierarchy of the current page — use breadcrumbs instead.
03

Examples

Completed (terminal state)

Passing `currentStep={steps.length}` advances past the final step, marking every step complete — the terminal "done" state shown after a flow finishes.

Interactive steps

A step becomes navigable when its `StepItem` carries an `href` (renders the body as a link) or an `onclick` (renders it as a button). The marker and connector stay decorative — only the body region is the focusable, clickable target.

Skipped step

Use `state: "skipped"` when a flow advances past a step without completing it.

Vertical orientation

Set `orientation="vertical"` to stack the steps top-to-bottom with the connector running down the side — useful in narrow side panels or wizards.

04

Props

Props for steps
Name Type Default Required Bindable Description
steps StepItem[] req Ordered list of step entries from first to last.
currentStep number req Zero-based index of the active step. Steps with index < currentStep are "completed". Pass steps.length to mark every step as complete (terminal "done" state).
orientation 'horizontal' | 'vertical' 'horizontal' Layout direction. Defaults to 'horizontal'.
label text 'Progress' Accessible name for the wrapping nav landmark. Defaults to 'Progress'.
completedLabel text 'Completed' Visually-hidden text prepended to completed steps so screen readers announce state + label. Defaults to 'Completed'.
skippedLabel text 'Skipped' Visually-hidden text prepended to skipped steps so screen readers announce state + label. Defaults to 'Skipped'.