Steps
Overview
The Steps component provides a multi-step progress indicator for wizard flows, checkout processes, or any multi-step workflow.
It supports horizontal and vertical layouts, customizable markers, and clickable navigation.
Import
import { Steps } from '@allxsmith/bestax-bulma';
Usage
Basic Steps
A simple step indicator showing progress through a flow.
<Steps value={1} items={[{ label: 'Account' }, { label: 'Profile' }, { label: 'Complete' }]} />
Clickable Steps
Steps that allow navigation by clicking.
function example() { const [step, setStep] = useState(1); return ( <Block> <Steps value={step} items={[ { label: 'Account', clickable: true }, { label: 'Profile', clickable: true }, { label: 'Review', clickable: true }, { label: 'Complete', clickable: true }, ]} onStepClick={setStep} color="primary" /> <Paragraph mt="4">Current step: {step + 1}</Paragraph> </Block> ); }
Color Variants
Steps with different color variants.
<Block display="flex" flexDirection="column"> <Steps value={1} color="primary" items={[{ label: 'Step 1' }, { label: 'Step 2' }, { label: 'Step 3' }]} /> <Steps value={1} color="success" items={[{ label: 'Step 1' }, { label: 'Step 2' }, { label: 'Step 3' }]} /> <Steps value={1} color="info" items={[{ label: 'Step 1' }, { label: 'Step 2' }, { label: 'Step 3' }]} /> <Steps value={1} color="warning" items={[{ label: 'Step 1' }, { label: 'Step 2' }, { label: 'Step 3' }]} /> <Steps value={1} color="danger" items={[{ label: 'Step 1' }, { label: 'Step 2' }, { label: 'Step 3' }]} /> </Block>
Size Variants
Steps with different size variants.
<Block display="flex" flexDirection="column"> <Steps value={1} size="small" items={[{ label: 'Step 1' }, { label: 'Step 2' }, { label: 'Step 3' }]} /> <Steps value={1} items={[{ label: 'Step 1' }, { label: 'Step 2' }, { label: 'Step 3' }]} /> <Steps value={1} size="medium" items={[{ label: 'Step 1' }, { label: 'Step 2' }, { label: 'Step 3' }]} /> <Steps value={1} size="large" items={[{ label: 'Step 1' }, { label: 'Step 2' }, { label: 'Step 3' }]} /> </Block>
With Icons
Steps with custom icons in markers.
<Steps value={1} color="info" items={[ { label: 'Cart', icon: <Icon name="shopping-cart" variant="solid" /> }, { label: 'Shipping', icon: <Icon name="truck" variant="solid" /> }, { label: 'Payment', icon: <Icon name="credit-card" variant="solid" /> }, { label: 'Done', icon: <Icon name="check" variant="solid" /> }, ]} />
Vertical Layout
Steps in vertical orientation.
<Steps value={1} vertical color="primary" items={[ { label: 'Create Account' }, { label: 'Set Up Profile' }, { label: 'Choose Plan' }, { label: 'Start Using' }, ]} />
Rounded Markers
Steps with rounded (circular) markers.
<Steps value={2} rounded color="success" items={[ { label: 'Order Placed' }, { label: 'Processing' }, { label: 'Shipped' }, { label: 'Delivered' }, ]} />
Checkout Flow Example
A complete checkout flow with navigation buttons.
function example() { const [step, setStep] = useState(0); const steps = ['Cart', 'Shipping', 'Payment', 'Confirm']; return ( <Block> <Steps value={step} items={steps.map((label, i) => ({ label, clickable: i <= step }))} onStepClick={s => s <= step && setStep(s)} color="primary" /> <Box mt="4" p="4"> <Title size="5">{steps[step]}</Title> <Paragraph>Content for the {steps[step]} step goes here.</Paragraph> </Box> <Buttons mt="4"> <Button onClick={() => setStep(Math.max(0, step - 1))} disabled={step === 0} > Previous </Button> <Button color="primary" onClick={() => setStep(Math.min(3, step + 1))} disabled={step === 3} > {step === 2 ? 'Place Order' : 'Next'} </Button> </Buttons> </Block> ); }
Right-to-Left
In a right-to-left page the steps run from the right, and the lines and the label gaps follow them. labelPosition="right" and "left" mean the end and the start of the line, so in this vertical example each label sits to the left of its marker.
<div dir="rtl" lang="ar"> <Steps value={1} color="primary" items={[{ label: 'الحساب' }, { label: 'الملف الشخصي' }, { label: 'تم' }]} /> <Steps value={1} vertical labelPosition="right" color="primary" items={[{ label: 'الحساب' }, { label: 'الملف الشخصي' }, { label: 'تم' }]} /> </div>
Compound (dot-notation) usage
Step is also available as Steps.Step, so steps can be declared as children from the single Steps import — an alternative to the items prop.
<Steps value={1}> <Steps.Step label="Account" /> <Steps.Step label="Profile" /> <Steps.Step label="Complete" /> </Steps>
Accessibility
- The active step has
aria-current="step", on its list item, or on its button when it's clickable - A clickable step stays a list item and puts its marker and label in a
<button type="button">inside it, so the list keeps its list items and assistive technology can count them. The button takes Tab, Enter and Space, and the focus ring goes around the whole step, which is what you can click - The list has
role="list". That's the role a<ul>already has, set again for Safari, whose WebKit stops exposing a<ul>as a list once its markers are hidden, as they are here, unless the role is written out - Use descriptive labels for each step
- The step markers show completion state with checkmarks
- In forced colors (Windows' contrast themes), the lines and a completed step's fill are drawn in the theme's text color, and the current step's marker gets an outline, so completed, current and upcoming steps still look different without color
Related Components
- Progress - For linear progress indication
Additional Resources
Use the onStepClick callback with clickable: true on items to allow users to navigate back to previous steps.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
value | number | 0 | Current active step (0-indexed). |
items | StepItemProps[] | — | Array of step items. |
size | 'small' | 'medium' | 'large' | — | Size of the steps. |
color | 'primary' | 'link' | 'info' | 'success' | 'warning' | 'danger' | — | Color variant. |
hasMarker | boolean | true | Show step markers. Default: true. |
animated | boolean | true | Enable animations. Default: true. |
rounded | boolean | true | Use rounded markers. Default: true. |
vertical | boolean | false | Vertical layout. |
labelPosition | 'bottom' | 'right' | 'left' | 'bottom' | Position of labels. right and left mean the end and the start of the line, so in a right-to-left page right puts each label to the left of its marker, and left to the right. |
mobileMode | 'minimal' | 'compact' | 'right' | — | Mobile display mode. |
showStepNumbers | boolean | true | Displays step numbers in the markers. |
hasNavigation | boolean | false | Shows previous/next navigation buttons. They render type="button", so a multi-step form wrapped around the steps is not submitted by moving between them. |
prevLabel | string | — | Label for the previous button. |
nextLabel | string | — | Label for the next button. |
onPrev | () => void | — | Callback when previous button is clicked. |
onNext | () => void | — | Callback when next button is clicked. |
onStepClick | (step: number) => void | — | Callback when a step is clicked. |
children | React.ReactNode | — | Step children (alternative to items). |
className | string | — | Additional CSS classes. |
... | All standard <div> attributes and Bulma helper props | — | See Helper Props |
Subcomponents:
Steps.Step: Individual Step component for use inside Steps.
Steps.Step
| Prop | Type | Default | Description |
|---|---|---|---|
isActive | boolean | false | Whether this step is active |
isCompleted | boolean | false | Whether this step is completed |
label | React.ReactNode | — | Step label/title, or pass it as children. On a clickable step it's rendered inside the step's <button>, so it has to be phrasing content, like text, a <span> or an icon, with no link, button or other control in it. |
icon | React.ReactNode | — | Icon for the step marker |
clickable | boolean | false | Whether this step is clickable. A clickable step puts its marker and label in a <button type="button"> inside the <li>, which calls onClick, and aria-current goes on that button. The <li> keeps the rest of the props. |
onClick | () => void | — | Click handler |
stepNumber | number | — | Step number to display in marker (1-indexed) |
completedIcon | React.ReactNode | '✓' | Icon shown when the step is completed. |
className | string | — | Additional CSS classes. |
children | React.ReactNode | — | Content rendered inside the component. |
... | All standard <li> attributes and Bulma helper props | — | See Helper Props |
StepItemProps
| Prop | Type | Default | Description |
|---|---|---|---|
label | React.ReactNode | — | Step label/title. On a clickable step it's rendered inside the step's <button>, so it has to be phrasing content, like text, a <span> or an icon, with no link, button or other control in it. |
icon | React.ReactNode | — | Icon for the step marker. |
clickable | boolean | false | Whether this step is clickable. A clickable step puts its marker and label in a <button type="button"> inside its list item, which calls onStepClick. |
completedIcon | React.ReactNode | '✓' | Icon shown when the step is completed. |
className | string | — | Additional class for this step. |
CSS & Sass Variables
Steps registers these variables on its own .steps element. Override them there (or via className) — a value set on an ancestor is only inherited, and loses to the component-level declaration. See Theme.
| CSS Variable | Sass Variable | Default |
|---|---|---|
--bulma-steps-marker-size | $steps-marker-size | 2rem |
--bulma-steps-marker-size-small | $steps-marker-size-small | 1.5rem |
--bulma-steps-marker-size-medium | $steps-marker-size-medium | 2.5rem |
--bulma-steps-marker-size-large | $steps-marker-size-large | 3rem |
--bulma-steps-divider-height | $steps-divider-height | 0.2em |
--bulma-steps-default-color | $steps-default-color | var(--bulma-grey-light) |
--bulma-steps-marker-background | $steps-marker-background | var(--bulma-scheme-main) |
--bulma-steps-marker-font-size | $steps-marker-font-size | var(--bulma-size-small) |
--bulma-steps-marker-font-weight | $steps-marker-font-weight | var(--bulma-weight-bold) |
--bulma-steps-title-size | $steps-title-size | var(--bulma-size-small) |
--bulma-steps-title-weight | $steps-title-weight | var(--bulma-weight-medium) |
--bulma-steps-title-color | $steps-title-color | var(--bulma-text-weak) |
--bulma-steps-title-active-color | $steps-title-active-color | var(--bulma-text-strong) |
--bulma-steps-title-active-weight | $steps-title-active-weight | var(--bulma-weight-semibold) |
--bulma-steps-content-margin-top | $steps-content-margin-top | 0.5rem |
--bulma-steps-vertical-padding | $steps-vertical-padding | 1.5rem |
--bulma-steps-vertical-content-margin-left | $steps-vertical-content-margin-left | 1rem |
--bulma-steps-animation-duration | $steps-animation-duration | 0.3s |
--bulma-steps-navigation-margin-top | $steps-navigation-margin-top | 1rem |