{"slug":"steps","title":"Steps","description":"Using the steps machine in your project.","contentType":"component","framework":"react","content":"Steps guide users through a multi-step process.\n\n## Resources\n\n\n[Latest version: v1.35.3](https://www.npmjs.com/package/@zag-js/steps)\n[Logic Visualizer](https://zag-visualizer.vercel.app/steps)\n[Source Code](https://github.com/chakra-ui/zag/tree/main/packages/machines/steps)\n\n\n\n**Features**\n\n- Supports horizontal and vertical orientations\n- Supports changing the active step with the keyboard and pointer\n- Supports linear and non-linear steps\n\n## Installation\n\nInstall the steps package:\n\n```bash\nnpm install @zag-js/steps @zag-js/react\n# or\nyarn add @zag-js/steps @zag-js/react\n```\n\n## Anatomy\n\nCheck the steps anatomy and part names.\n\n> Each part includes a `data-part` attribute to help identify them in the DOM.\n\n\n\n## Usage\n\nImport the steps package:\n\n```jsx\nimport * as steps from \"@zag-js/steps\"\n```\n\nThe steps package exports two key functions:\n\n- `machine` - State machine logic.\n- `connect` - Maps machine state to JSX props and event handlers.\n\nThen use the framework integration helpers:\n\n```jsx\nimport * as steps from \"@zag-js/steps\"\nimport { useMachine, normalizeProps } from \"@zag-js/react\"\nimport { useId } from \"react\"\n\nconst stepsData = [\n  { title: \"Step 1\" },\n  { title: \"Step 2\" },\n  { title: \"Step 3\" },\n]\n\nfunction Steps() {\n  const service = useMachine(steps.machine, {\n    id: useId(),\n    count: stepsData.length,\n  })\n\n  const api = steps.connect(service, normalizeProps)\n\n  return (\n    <div {...api.getRootProps()}>\n      <div {...api.getListProps()}>\n        {stepsData.map((step, index) => (\n          <div key={index} {...api.getItemProps({ index })}>\n            <button {...api.getTriggerProps({ index })}>\n              <div {...api.getIndicatorProps({ index })}>{index + 1}</div>\n              <span>{step.title}</span>\n            </button>\n            <div {...api.getSeparatorProps({ index })} />\n          </div>\n        ))}\n      </div>\n\n      {stepsData.map((step, index) => (\n        <div key={index} {...api.getContentProps({ index })}>\n          {step.title}\n        </div>\n      ))}\n\n      <div {...api.getContentProps({ index: stepsData.length })}>\n        Steps Complete - Thank you for filling out the form!\n      </div>\n\n      <div>\n        <button {...api.getPrevTriggerProps()}>Back</button>\n        <button {...api.getNextTriggerProps()}>Next</button>\n      </div>\n    </div>\n  )\n}\n```\n\n## Setting the initial step\n\nSet the initial step by passing `defaultStep` to the machine context.\n\n> The value of the `step` property is zero-based index.\n\n```jsx {2}\nconst service = useMachine(steps.machine, {\n  defaultStep: 1,\n})\n```\n\n## Controlled current step\n\nUse `step` and `onStepChange` for controlled usage.\n\n```jsx\nconst service = useMachine(steps.machine, {\n  step,\n  onStepChange(details) {\n    setStep(details.step)\n  },\n})\n```\n\n## Listening for step change\n\nWhen the active step changes, the machine will invoke the `onStepChange` event\n\n```jsx {2-4}\nconst service = useMachine(steps.machine, {\n  onStepChange(details) {\n    // details => { step: number }\n    console.log(`Step changed to ${details.step}`)\n  },\n})\n```\n\n## Listening for steps completion\n\nWhen all steps are completed, the machine will invoke the `onStepComplete` event\n\n```jsx {2-4}\nconst service = useMachine(steps.machine, {\n  onStepComplete() {\n    console.log(\"All steps are complete\")\n  },\n})\n```\n\n## Enforcing linear steps\n\nTo enforce linear steps, you can set the `linear` prop to `true` when creating\nthe steps machine. This will prevent users from skipping steps.\n\n```jsx {2}\nconst service = useMachine(steps.machine, {\n  linear: true,\n})\n```\n\n## Validating steps in linear mode\n\nUse `isStepValid` to block forward navigation when a step is incomplete.\n\n```jsx\nconst service = useMachine(steps.machine, {\n  linear: true,\n  isStepValid(index) {\n    return completedSteps.has(index)\n  },\n  onStepInvalid(details) {\n    // details => { step: number, action: \"next\" | \"set\", targetStep?: number }\n    console.log(\"blocked at step\", details.step)\n  },\n})\n```\n\n## Skipping optional steps\n\nUse `isStepSkippable` when some steps should be bypassed by next/prev\nnavigation.\n\n```jsx\nconst service = useMachine(steps.machine, {\n  isStepSkippable(index) {\n    return index === 2\n  },\n})\n```\n\n## Changing the orientation\n\nThe steps machine supports both horizontal and vertical orientations. You can\nset the `orientation` prop to `horizontal` or `vertical` to change the\norientation of the steps.\n\n```jsx {2}\nconst service = useMachine(steps.machine, {\n  orientation: \"vertical\",\n})\n```\n\n## Programmatic navigation\n\nUse the API methods to move through the flow in code.\n\n```jsx\napi.setStep(2)\napi.goToNextStep()\napi.goToPrevStep()\napi.resetStep()\n```\n\n## Styling guide\n\nEach part includes a `data-part` attribute you can target in CSS.\n\n```css\n[data-scope=\"steps\"][data-part=\"root\"] {\n  /* styles for the root part */\n}\n\n[data-scope=\"steps\"][data-part=\"root\"][data-orientation=\"horizontal|vertical\"] {\n  /* styles for the root part based on orientation */\n}\n\n[data-scope=\"steps\"][data-part=\"list\"] {\n  /* styles for the list part */\n}\n\n[data-scope=\"steps\"][data-part=\"list\"][data-orientation=\"horizontal|vertical\"] {\n  /* styles for the list part based on orientation */\n}\n\n[data-scope=\"steps\"][data-part=\"separator\"] {\n  /* styles for the separator part */\n}\n\n[data-scope=\"steps\"][data-part=\"separator\"][data-orientation=\"horizontal|vertical\"] {\n  /* styles for the separator part based on orientation */\n}\n```\n\n### Current step\n\nTo style the current step, you can use the `data-current` attribute.\n\n```css\n[data-scope=\"steps\"][data-part=\"item\"][data-current] {\n  /* item styles for the current step */\n}\n\n[data-scope=\"steps\"][data-part=\"separator\"][data-current] {\n  /* separator styles for the current step */\n}\n```\n\n### Completed step\n\nTo style the completed step, you can use the `data-complete` attribute.\n\n```css\n[data-scope=\"steps\"][data-part=\"item\"][data-complete] {\n  /* item styles for the completed step */\n}\n\n[data-scope=\"steps\"][data-part=\"separator\"][data-complete] {\n  /* separator styles for the completed step */\n}\n```\n\n### Incomplete step\n\nTo style the incomplete step, you can use the `data-incomplete` attribute.\n\n```css\n[data-scope=\"steps\"][data-part=\"item\"][data-incomplete] {\n  /* item styles for the incomplete step */\n}\n\n[data-scope=\"steps\"][data-part=\"separator\"][data-incomplete] {\n  /* separator styles for the incomplete step */\n}\n```\n\n## Methods and Properties\n\n### Machine Context\n\nThe steps machine exposes the following context properties:\n\n**`ids`**\nType: `ElementIds`\nDescription: The custom ids for the stepper elements\n\n**`step`**\nType: `number`\nDescription: The controlled value of the stepper\n\n**`defaultStep`**\nType: `number`\nDescription: The initial value of the stepper when rendered.\nUse when you don't need to control the value of the stepper.\n\n**`onStepChange`**\nType: `(details: StepChangeDetails) => void`\nDescription: Callback to be called when the value changes\n\n**`onStepComplete`**\nType: `VoidFunction`\nDescription: Callback to be called when a step is completed\n\n**`linear`**\nType: `boolean`\nDescription: If `true`, the stepper requires the user to complete the steps in order\n\n**`orientation`**\nType: `\"horizontal\" | \"vertical\"`\nDescription: The orientation of the stepper\n\n**`count`**\nType: `number`\nDescription: The total number of steps\n\n**`isStepValid`**\nType: `(index: number) => boolean`\nDescription: Whether a step is valid. Invalid steps block forward navigation in linear mode.\n\n**`isStepSkippable`**\nType: `(index: number) => boolean`\nDescription: Whether a step can be skipped during navigation.\nSkippable steps are bypassed when using next/prev.\n\n**`onStepInvalid`**\nType: `(details: StepInvalidDetails) => void`\nDescription: Called when navigation is blocked due to an invalid step.\n\n**`dir`**\nType: `\"ltr\" | \"rtl\"`\nDescription: The document's text/writing direction.\n\n**`id`**\nType: `string`\nDescription: The unique identifier of the machine.\n\n**`getRootNode`**\nType: `() => ShadowRoot | Node | Document`\nDescription: A root node to correctly resolve document in custom environments. E.x.: Iframes, Electron.\n\n### Machine API\n\nThe steps `api` exposes the following methods:\n\n**`value`**\nType: `number`\nDescription: The value of the stepper.\n\n**`percent`**\nType: `number`\nDescription: The percentage of the stepper.\n\n**`count`**\nType: `number`\nDescription: The total number of steps.\n\n**`hasNextStep`**\nType: `boolean`\nDescription: Whether the stepper has a next step.\n\n**`hasPrevStep`**\nType: `boolean`\nDescription: Whether the stepper has a previous step.\n\n**`isCompleted`**\nType: `boolean`\nDescription: Whether the stepper is completed.\n\n**`isStepValid`**\nType: `(index: number) => boolean`\nDescription: Check if a specific step is valid (lazy evaluation)\n\n**`isStepSkippable`**\nType: `(index: number) => boolean`\nDescription: Check if a specific step can be skipped\n\n**`setStep`**\nType: `(step: number) => void`\nDescription: Function to set the value of the stepper.\n\n**`goToNextStep`**\nType: `VoidFunction`\nDescription: Function to go to the next step.\n\n**`goToPrevStep`**\nType: `VoidFunction`\nDescription: Function to go to the previous step.\n\n**`resetStep`**\nType: `VoidFunction`\nDescription: Function to go to reset the stepper.\n\n**`getItemState`**\nType: `(props: ItemProps) => ItemState`\nDescription: Returns the state of the item at the given index.\n\n### Data Attributes\n\n**`Root`**\n\n**`data-scope`**: steps\n**`data-part`**: root\n**`data-orientation`**: The orientation of the steps\n\n**`List`**\n\n**`data-scope`**: steps\n**`data-part`**: list\n**`data-orientation`**: The orientation of the list\n\n**`Item`**\n\n**`data-scope`**: steps\n**`data-part`**: item\n**`data-orientation`**: The orientation of the item\n**`data-skippable`**: \n\n**`Trigger`**\n\n**`data-scope`**: steps\n**`data-part`**: trigger\n**`data-state`**: \"open\" | \"closed\"\n**`data-orientation`**: The orientation of the trigger\n**`data-complete`**: Present when the trigger value is complete\n**`data-current`**: Present when current\n**`data-incomplete`**: \n\n**`Content`**\n\n**`data-scope`**: steps\n**`data-part`**: content\n**`data-state`**: \"open\" | \"closed\"\n**`data-orientation`**: The orientation of the content\n\n**`Indicator`**\n\n**`data-scope`**: steps\n**`data-part`**: indicator\n**`data-complete`**: Present when the indicator value is complete\n**`data-current`**: Present when current\n**`data-incomplete`**: \n\n**`Separator`**\n\n**`data-scope`**: steps\n**`data-part`**: separator\n**`data-orientation`**: The orientation of the separator\n**`data-complete`**: Present when the separator value is complete\n**`data-current`**: Present when current\n**`data-incomplete`**: \n\n**`Progress`**\n\n**`data-scope`**: steps\n**`data-part`**: progress\n**`data-complete`**: Present when the progress value is complete\n\n### CSS Variables\n\n<CssVarTable name=\"steps\" />","package":"@zag-js/steps","editUrl":"https://github.com/chakra-ui/zag/edit/main/website/data/components/steps.mdx"}