Stepper
Multi-step flow indicator. Horizontal, compact, vertical, with progress bar, and error states.
Overview
The Stepper component is a core building block of the Byteion design system, providing a robust, accessibility-compliant interface for its specific UI capabilities.
Why this exists
Steppers guide users through multi-step processes, reducing cognitive load by showing only one step at a time while maintaining context of the overall flow.
Mental model
A stepper is a progress indicator for multi-step flows. It shows completed, current, and upcoming steps. Users typically move forward sequentially.
When to use
When not to use
Basic example
The following example demonstrates standard usage, fully compliant with Byteion's token-first approach.
Horizontal with labels
-
Account
Completed
-
Plan
In progress
-
3
Billing
Pending
-
4
Confirm
Pending
Compact
- 3
- 4
- 5
With progress bar
Step 2 of 4 — Plan
50%Vertical
-
Account created
2 minutes ago
Welcome aboard! Your account is ready to use.
-
Choose your plan
In progress
Pick the plan that fits your team. You can change it anytime.
-
3
Add payment method
Pending
With error step
-
Upload
Completed
-
Verify
Failed — retry
-
3
Publish
Pending
import { Stepper, StepperProgress } from '@byteion/react';
const steps = [
{ id: '1', label: 'Account', description: 'Email + password' },
{ id: '2', label: 'Profile', description: 'Name + photo' },
{ id: '3', label: 'Workspace', description: 'Invite teammates' },
];
export default function StepperDemo() {
return (
<div className="space-y-10 p-6">
<Stepper steps={steps} current={1} />
<StepperProgress steps={steps} current={1} />
</div>
);
}
<script setup lang="ts">
import { Stepper } from '@byteion/vue';
const steps = [
{ id: '1', label: 'Account', description: 'Email + password' },
{ id: '2', label: 'Profile', description: 'Name + photo' },
{ id: '3', label: 'Workspace', description: 'Invite teammates' },
];
</script>
<template>
<div class="space-y-10 p-6">
<Stepper :steps="steps" :current="1" />
</div>
</template>
Variants
Each variant communicates a different meaning. Choose based on priority, not aesthetics.
Single default variant.
Sizes
Size should match the importance and context of the component.
- md — md size.
States
This component reacts seamlessly to the following interaction and data states:
- complete — complete state.
- current — current state.
- pending — pending state.
- error — Validation failed — red border and error message.
- default — Resting appearance before interaction.
- hover — Pointer is over the element — visual feedback via color or shadow.
- focus — Keyboard or tab focus — shows ring indicator for accessibility.
- active — Currently selected or in use.
- disabled — Non-interactive — grayed out, cursor not-allowed.
Anatomy
Usage guidelines
- Limit to 7 steps maximum.
- Allow going back to previous steps.
- Save progress between steps.
Do and Don't
Do
- Limit to 7 steps.
- Allow back navigation.
- Save between steps.
Don't
- Do not exceed 7 steps.
- Do not skip steps.
- Do not lose data between steps.
Accessibility
Each step is a link or button. Current step has aria-current="step". Completed steps are navigable.
Role:list
Customization
Active step color follows --primary. Completed uses --success.
Compose with React cva()
Use the exportedcva() +cn() utilities to compose your own variant on top of the Byteion tokens.
import { cva, cn, type VariantProps } from '@byteion/react';
const myStepper = cva('base classes…', {
variants: {
accent: { soft:'border-primary-200', loud:'border-primary-500' },
},
defaultVariants: { accent:'soft' },
});
type Props = React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof myStepper>;
Compose with Vue cva()
Use the exportedcva() +cn() utilities inside standard Vue setup blocks.
<script setup lang="ts">
import { computed, useAttrs } from 'vue';
import { cva, type VariantProps } from '@byteion/vue';
interface Props { accent?:'soft' |'loud' }
const props = withDefaults(defineProps<Props>(), { accent:'soft' });
const attrs = useAttrs();
const myStepper = cva('base classes…', {
variants: { accent: { soft:'border-primary-200', loud:'border-primary-500' } },
});
const cls = computed(() => myStepper({ accent: props.accent, class: attrs.class as string | undefined }));
</script>
Runtime events
Byteion keeps framework APIs idiomatic: HTML uses DOM custom events, React uses callback props, and Vue uses emitted events / v-model updates.
HTML / JS events
No HTML runtime events are declared by this adapter.
React callbacks
No React callback events are declared by this adapter.
Vue emits
No Vue emitted events are declared by this adapter.
Remote / AJAX
This component does not implement Byteion JS remote loading. Use normal HTML form submission, framework state, or your application data layer around it.
API Reference
Static HTML. Step navigation controlled by parent flow logic.
HTML Data Attributes
No custom data attributes required.
React Props · StepperProps
Extracted directly fromreact/src/components/Stepper.tsx.
export interface StepperProps extends Omit<HTMLAttributes<HTMLOListElement>, 'children'> {
steps: StepperStep[];
/** 0-based index of the active step. Used only when `steps[i].state` is unset. */
currentStep?: number;
/** Layout. */
orientation?: 'horizontal' | 'vertical' | 'compact';
}
Vue Props · StepperProps
Extracted directly fromvue/src/components/Stepper.vue.
export interface StepperProps {
steps: StepperStep[];
/** 0-based index of the active step. Used only when `steps[i].state` is unset. */
currentStep?: number;
/** Layout. */
orientation?: 'horizontal' | 'vertical' | 'compact';
}
Developer tips
state: 'error' on steps with failed validation to surface errors visually.Common mistakes
- Treating Stepper as a general navigation menu — use Navbar or Sidebar instead.
- Showing too many steps horizontally — 3–5 is ideal; beyond that, group or switch to vertical.
- Using long labels in horizontal mode — labels truncate or overflow; keep them short.
- Allowing users to jump to locked future steps — always validate before enabling forward navigation.
- Not showing failed validation in the stepper — update the failed step to
state: 'error'. - Losing entered form data between steps — preserve input in state or store.
- Relying only on color for state — use checkmark, X, and number differences for accessibility.
- Forgetting that
currentStepis 0-based — step 1 = index 0.
Production usage tips
- For Laravel or server-rendered flows, keep the step in the route or query string so deep linking and page refresh work predictably.
- For React/Vue SPAs, keep step state in component state, a store (Pinia/Zustand), or the router.
- Coordinate stepper state with form validation, loading state, dirty state, error state, and submit state.
- Test every transition: first step → next, middle step → next/prev, last step → submit, error step → retry, and the complete flow end-to-end.
- Test with keyboard navigation, focus movement, dark mode, and branded themes.
- Persist draft data for long onboarding or checkout flows — localStorage or server-side drafts.
- Use the canonical HTML structure as the source of truth; keep React and Vue wrappers aligned with the documented orientations and states.
Premium examples
Advanced patterns available in Byteion Pro:
Related components
- Button — advance or submit step actions
- Alert — show per-step validation or error messages
- Form Field — wrap stepper content in validated forms
- Input — collect step-level data
- Card — contain each step's content
- Progress — standalone progress indicator
- Tabs — non-sequential section switching
- Modal — lightweight stepped flows in dialogs
- Pagination — page-based navigation (not for multi-step flows)
Unlock Premium Patterns
Get access to copy-paste ready Pro blocks, SaaS templates, and advanced data-tables built with this component.
Explore Pro Components