Skip to main content

Steps guide users through a multi-step process.

Loading...

Features

  • Supports horizontal and vertical orientations
  • Supports changing the active step with the keyboard and pointer
  • Supports linear and non-linear steps

Installation

Install the steps package:

npm install @zag-js/steps @zag-js/vue # or yarn add @zag-js/steps @zag-js/vue

Anatomy

Check the steps anatomy and part names.

Each part includes a data-part attribute to help identify them in the DOM.

Usage

Import the steps package:

import * as steps from "@zag-js/steps"

The steps package exports two key functions:

  • machine - State machine logic.
  • connect - Maps machine state to JSX props and event handlers.

Then use the framework integration helpers:

<script setup> import * as steps from "@zag-js/steps" import { useMachine, normalizeProps } from "@zag-js/vue" import { computed } from "vue" const stepsData = [ { title: "Step 1" }, { title: "Step 2" }, { title: "Step 3" }, ] const service = useMachine(steps.machine, { id: "1", count: stepsData.length, }) const api = computed(() => steps.connect(service, normalizeProps)) </script> <template> <div v-bind="api.getRootProps()"> <div v-bind="api.getListProps()"> <div v-for="(step, index) in stepsData" :key="index" v-bind="api.getItemProps({ index })" > <button v-bind="api.getTriggerProps({ index })"> <div v-bind="api.getIndicatorProps({ index })">{{ index + 1 }}</div> <span>{{ step.title }}</span> </button> <div v-bind="api.getSeparatorProps({ index })" /> </div> </div> <div v-for="(step, index) in stepsData" :key="index" v-bind="api.getContentProps({ index })" > {{ step.title }} - {{ step.description }} </div> <div v-bind="api.getContentProps({ index: stepsData.length })"> Steps Complete - Thank you for filling out the form! </div> <div> <button v-bind="api.getPrevTriggerProps()">Back</button> <button v-bind="api.getNextTriggerProps()">Next</button> </div> </div> </template>

Setting the initial step

Set the initial step by passing defaultStep to the machine context.

The value of the step property is zero-based index.

const service = useMachine(steps.machine, { defaultStep: 1, })

Controlled current step

Use step and onStepChange for controlled usage.

const service = useMachine(steps.machine, { step, onStepChange(details) { setStep(details.step) }, })

Listening for step change

When the active step changes, the machine will invoke the onStepChange event

const service = useMachine(steps.machine, { onStepChange(details) { // details => { step: number } console.log(`Step changed to ${details.step}`) }, })

Listening for steps completion

When all steps are completed, the machine will invoke the onStepComplete event

const service = useMachine(steps.machine, { onStepComplete() { console.log("All steps are complete") }, })

Enforcing linear steps

To enforce linear steps, you can set the linear prop to true when creating the steps machine. This will prevent users from skipping steps.

const service = useMachine(steps.machine, { linear: true, })

Validating steps in linear mode

Use isStepValid to block forward navigation when a step is incomplete.

const service = useMachine(steps.machine, { linear: true, isStepValid(index) { return completedSteps.has(index) }, onStepInvalid(details) { // details => { step: number, action: "next" | "set", targetStep?: number } console.log("blocked at step", details.step) }, })

Skipping optional steps

Use isStepSkippable when some steps should be bypassed by next/prev navigation.

const service = useMachine(steps.machine, { isStepSkippable(index) { return index === 2 }, })

Changing the orientation

The steps machine supports both horizontal and vertical orientations. You can set the orientation prop to horizontal or vertical to change the orientation of the steps.

const service = useMachine(steps.machine, { orientation: "vertical", })

Programmatic navigation

Use the API methods to move through the flow in code.

api.setStep(2) api.goToNextStep() api.goToPrevStep() api.resetStep()

Styling guide

Each part includes a data-part attribute you can target in CSS.

[data-scope="steps"][data-part="root"] { /* styles for the root part */ } [data-scope="steps"][data-part="root"][data-orientation="horizontal|vertical"] { /* styles for the root part based on orientation */ } [data-scope="steps"][data-part="list"] { /* styles for the list part */ } [data-scope="steps"][data-part="list"][data-orientation="horizontal|vertical"] { /* styles for the list part based on orientation */ } [data-scope="steps"][data-part="separator"] { /* styles for the separator part */ } [data-scope="steps"][data-part="separator"][data-orientation="horizontal|vertical"] { /* styles for the separator part based on orientation */ }

Current step

To style the current step, you can use the data-current attribute.

[data-scope="steps"][data-part="item"][data-current] { /* item styles for the current step */ } [data-scope="steps"][data-part="separator"][data-current] { /* separator styles for the current step */ }

Completed step

To style the completed step, you can use the data-complete attribute.

[data-scope="steps"][data-part="item"][data-complete] { /* item styles for the completed step */ } [data-scope="steps"][data-part="separator"][data-complete] { /* separator styles for the completed step */ }

Incomplete step

To style the incomplete step, you can use the data-incomplete attribute.

[data-scope="steps"][data-part="item"][data-incomplete] { /* item styles for the incomplete step */ } [data-scope="steps"][data-part="separator"][data-incomplete] { /* separator styles for the incomplete step */ }

Methods and Properties

Machine Context

The steps machine exposes the following context properties:

  • idsElementIdsThe custom ids for the stepper elements
  • stepnumberThe controlled value of the stepper
  • defaultStepnumberThe initial value of the stepper when rendered. Use when you don't need to control the value of the stepper.
  • onStepChange(details: StepChangeDetails) => voidCallback to be called when the value changes
  • onStepCompleteVoidFunctionCallback to be called when a step is completed
  • linearbooleanIf `true`, the stepper requires the user to complete the steps in order
  • orientation"horizontal" | "vertical"The orientation of the stepper
  • countnumberThe total number of steps
  • isStepValid(index: number) => booleanWhether a step is valid. Invalid steps block forward navigation in linear mode.
  • isStepSkippable(index: number) => booleanWhether a step can be skipped during navigation. Skippable steps are bypassed when using next/prev.
  • onStepInvalid(details: StepInvalidDetails) => voidCalled when navigation is blocked due to an invalid step.
  • dir"ltr" | "rtl"The document's text/writing direction.
  • idstringThe unique identifier of the machine.
  • getRootNode() => ShadowRoot | Node | DocumentA root node to correctly resolve document in custom environments. E.x.: Iframes, Electron.

Machine API

The steps api exposes the following methods:

  • valuenumberThe value of the stepper.
  • percentnumberThe percentage of the stepper.
  • countnumberThe total number of steps.
  • hasNextStepbooleanWhether the stepper has a next step.
  • hasPrevStepbooleanWhether the stepper has a previous step.
  • isCompletedbooleanWhether the stepper is completed.
  • isStepValid(index: number) => booleanCheck if a specific step is valid (lazy evaluation)
  • isStepSkippable(index: number) => booleanCheck if a specific step can be skipped
  • setStep(step: number) => voidFunction to set the value of the stepper.
  • goToNextStepVoidFunctionFunction to go to the next step.
  • goToPrevStepVoidFunctionFunction to go to the previous step.
  • resetStepVoidFunctionFunction to go to reset the stepper.
  • getItemState(props: ItemProps) => ItemStateReturns the state of the item at the given index.

Data Attributes

Root
data-scope
steps
data-part
root
data-orientation
The orientation of the steps
List
data-scope
steps
data-part
list
data-orientation
The orientation of the list
Item
data-scope
steps
data-part
item
data-orientation
The orientation of the item
Trigger
data-scope
steps
data-part
trigger
data-state
"open" | "closed"
data-orientation
The orientation of the trigger
data-complete
Present when the trigger value is complete
data-current
Present when current
Content
data-scope
steps
data-part
content
data-state
"open" | "closed"
data-orientation
The orientation of the content
Indicator
data-scope
steps
data-part
indicator
data-complete
Present when the indicator value is complete
data-current
Present when current
Separator
data-scope
steps
data-part
separator
data-orientation
The orientation of the separator
data-complete
Present when the separator value is complete
data-current
Present when current
Progress
data-scope
steps
data-part
progress
data-complete
Present when the progress value is complete

CSS Variables

Root
--percent
The percent value for the Root
Edit this page on GitHub