Stepper

The Stepper component displays a wizard-like workflow by guiding users through the multi-step progression.

Usage#

import { Stepper } from 'primereact/stepper';
<Stepper>
    <Stepper.List>
        <Stepper.Step>
            <Stepper.Header />
            <Stepper.Separator />
        </Stepper.Step>
    <Stepper.Panels>
        <Stepper.Panel />
    </Stepper.Panels>
</Stepper>

Examples#

Horizontal#

Stepper requires two Stepper.List, Stepper.Step, Stepper.Panels and Stepper.Panel components as children which are displayed horizontally.

Content I
import { Stepper } from 'primereact/stepper';
 
export default function HorizontalDemo() {
    return (
        <div className="card flex justify-center">
            <Stepper value="1" className="basis-[50rem]">
                <Stepper.List>
                    <Stepper.Step value="1">
                        <Stepper.Header>
                            <Stepper.Number>1</Stepper.Number>
                            <Stepper.Title>Header I</Stepper.Title>
                        </Stepper.Header>
                        <Stepper.Separator />
                    </Stepper.Step>
                    <Stepper.Step value="2">
                        <Stepper.Header>
                            <Stepper.Number>2</Stepper.Number>
                            <Stepper.Title>Header II</Stepper.Title>
                        </Stepper.Header>
                        <Stepper.Separator />
                    </Stepper.Step>
                    <Stepper.Step value="3">
                        <Stepper.Header>
                            <Stepper.Number>3</Stepper.Number>
                            <Stepper.Title>Header III</Stepper.Title>
                        </Stepper.Header>
                    </Stepper.Step>
                </Stepper.List>
                <Stepper.Panels>
                    <Stepper.Panel value="1">
                        <div className="flex flex-col h-48">
                            <div className="border-2 border-dashed border-surface-200 dark:border-surface-700 rounded bg-surface-50 dark:bg-surface-950 flex-auto flex justify-center items-center font-medium">Content I</div>
                        </div>
                    </Stepper.Panel>
                    <Stepper.Panel value="2">
                        <div className="flex flex-col h-48">
                            <div className="border-2 border-dashed border-surface-200 dark:border-surface-700 rounded bg-surface-50 dark:bg-surface-950 flex-auto flex justify-center items-center font-medium">Content II</div>
                        </div>
                    </Stepper.Panel>
                    <Stepper.Panel value="3">
                        <div className="flex flex-col h-48">
                            <div className="border-2 border-dashed border-surface-200 dark:border-surface-700 rounded bg-surface-50 dark:bg-surface-950 flex-auto flex justify-center items-center font-medium">Content III</div>
                        </div>
                    </Stepper.Panel>
                </Stepper.Panels>
            </Stepper>
        </div>
    );
}

Vertical#

Stepper requires two Stepper.Item, Stepper.Step and Stepper.Panel components as children which are displayed vertically.

Content I
import { Motion } from '@primereact/core/motion';
import { StepperItemInstance } from '@primereact/types/shared/stepper';
import { Stepper } from 'primereact/stepper';
 
export default function VerticalDemo() {
    return (
        <div className="card ">
            <Stepper value="1">
                <Stepper.Item value="1">
                    {(instance: StepperItemInstance) => {
                        return (
                            <>
                                <Stepper.Step>
                                    <Stepper.Header>
                                        <Stepper.Number>1</Stepper.Number>
                                        <Stepper.Title>Header I</Stepper.Title>
                                    </Stepper.Header>
                                </Stepper.Step>
                                <Motion in={instance.active} name="p-toggleable-content">
                                    <Stepper.Panel>
                                        <Stepper.Separator />
                                        <Stepper.Content>
                                            <div className="flex flex-col h-48">
                                                <div className="border-2 border-dashed border-surface-200 dark:border-surface-700 rounded bg-surface-50 dark:bg-surface-950 flex-auto flex justify-center items-center font-medium">Content I</div>
                                            </div>
                                        </Stepper.Content>
                                    </Stepper.Panel>
                                </Motion>
                            </>
                        );
                    }}
                </Stepper.Item>
                <Stepper.Item value="2">
                    {(instance: StepperItemInstance) => {
                        return (
                            <>
                                <Stepper.Step>
                                    <Stepper.Header>
                                        <Stepper.Number>2</Stepper.Number>
                                        <Stepper.Title>Header II</Stepper.Title>
                                    </Stepper.Header>
                                </Stepper.Step>
                                <Motion in={instance.active} name="p-toggleable-content">
                                    <Stepper.Panel>
                                        <Stepper.Separator />
                                        <Stepper.Content>
                                            <div className="flex flex-col h-48">
                                                <div className="border-2 border-dashed border-surface-200 dark:border-surface-700 rounded bg-surface-50 dark:bg-surface-950 flex-auto flex justify-center items-center font-medium">Content II</div>
                                            </div>
                                        </Stepper.Content>
                                    </Stepper.Panel>
                                </Motion>
                            </>
                        );
                    }}
                </Stepper.Item>
                <Stepper.Item value="3">
                    {(instance: StepperItemInstance) => {
                        return (
                            <>
                                <Stepper.Step>
                                    <Stepper.Header>
                                        <Stepper.Number>3</Stepper.Number>
                                        <Stepper.Title>Header III</Stepper.Title>
                                    </Stepper.Header>
                                </Stepper.Step>
                                <Motion in={instance.active} name="p-toggleable-content">
                                    <Stepper.Panel>
                                        <Stepper.Content>
                                            <div className="flex flex-col h-48">
                                                <div className="border-2 border-dashed border-surface-200 dark:border-surface-700 rounded bg-surface-50 dark:bg-surface-950 flex-auto flex justify-center items-center font-medium">Content III</div>
                                            </div>
                                        </Stepper.Content>
                                    </Stepper.Panel>
                                </Motion>
                            </>
                        );
                    }}
                </Stepper.Item>
            </Stepper>
        </div>
    );
}

Linear#

Linear mode enforces step-by-step progression through the workflow, requiring users to complete the current step before proceeding to the next one. This ensures a controlled navigation flow through the process.

Content I
import { StepperPanelInstance } from '@primereact/types/shared/stepper';
import { Button } from 'primereact/button';
import { Stepper } from 'primereact/stepper';
 
export default function HorizontalDemo() {
    return (
        <div className="card flex justify-center">
            <Stepper defaultValue="1" linear className="basis-[50rem]">
                <Stepper.List>
                    <Stepper.Step value="1">
                        <Stepper.Header>
                            <Stepper.Number>1</Stepper.Number>
                            <Stepper.Title>Header I</Stepper.Title>
                        </Stepper.Header>
                        <Stepper.Separator />
                    </Stepper.Step>
                    <Stepper.Step value="2">
                        <Stepper.Header>
                            <Stepper.Number>2</Stepper.Number>
                            <Stepper.Title>Header II</Stepper.Title>
                        </Stepper.Header>
                        <Stepper.Separator />
                    </Stepper.Step>
                    <Stepper.Step value="3">
                        <Stepper.Header>
                            <Stepper.Number>3</Stepper.Number>
                            <Stepper.Title>Header III</Stepper.Title>
                        </Stepper.Header>
                    </Stepper.Step>
                </Stepper.List>
                <Stepper.Panels>
                    <Stepper.Panel asChild value="1">
                        {(instance: StepperPanelInstance) => {
                            const { stepper } = instance;
 
                            return (
                                <>
                                    <div className="flex flex-col h-48">
                                        <div className="border-2 border-dashed border-surface-200 dark:border-surface-700 rounded bg-surface-50 dark:bg-surface-950 flex-auto flex justify-center items-center font-medium">Content I</div>
                                    </div>
                                    <div className="flex pt-6 justify-end">
                                        <Button onClick={() => stepper?.setActiveStep('2')}>
                                            Next
                                            <i className="pi pi-arrow-right " />
                                        </Button>
                                    </div>
                                </>
                            );
                        }}
                    </Stepper.Panel>
                    <Stepper.Panel asChild value="2">
                        {(instance: StepperPanelInstance) => {
                            const { stepper } = instance;
 
                            return (
                                <>
                                    <div className="flex flex-col h-48">
                                        <div className="border-2 border-dashed border-surface-200 dark:border-surface-700 rounded bg-surface-50 dark:bg-surface-950 flex-auto flex justify-center items-center font-medium">Content II</div>
                                    </div>
                                    <div className="flex pt-6 justify-between">
                                        <Button severity="secondary" onClick={() => stepper?.setActiveStep('1')}>
                                            <i className="pi pi-arrow-left" />
                                            Back
                                        </Button>
                                        <Button onClick={() => stepper?.setActiveStep('3')}>
                                            Next
                                            <i className="pi pi-arrow-right" />
                                        </Button>
                                    </div>
                                </>
                            );
                        }}
                    </Stepper.Panel>
                    <Stepper.Panel asChild value="3">
                        {(instance: StepperPanelInstance) => {
                            const { stepper } = instance;
 
                            return (
                                <>
                                    <div className="flex flex-col h-48">
                                        <div className="border-2 border-dashed border-surface-200 dark:border-surface-700 rounded bg-surface-50 dark:bg-surface-950 flex-auto flex justify-center items-center font-medium">Content III</div>
                                    </div>
                                    <div className="pt-6 ">
                                        <Button severity="secondary" onClick={() => stepper?.setActiveStep('2')}>
                                            <i className="pi pi-arrow-left " />
                                            Back
                                        </Button>
                                    </div>
                                </>
                            );
                        }}
                    </Stepper.Panel>
                </Stepper.Panels>
            </Stepper>
        </div>
    );
}

Steps Only#

When you need a more compact UI, the steps-only mode displays just the step indicators without content panels. This is useful for indicating progress without showing the actual step content.

import { Stepper } from 'primereact/stepper';
 
export default function StepsOnlyDemo() {
    return (
        <div className="card flex justify-center">
            <Stepper value="1" className="basis-[50rem]">
                <Stepper.List>
                    <Stepper.Step value="1">
                        <Stepper.Header>
                            <Stepper.Number>1</Stepper.Number>
                            <Stepper.Title>Design</Stepper.Title>
                        </Stepper.Header>
                        <Stepper.Separator />
                    </Stepper.Step>
                    <Stepper.Step value="2">
                        <Stepper.Header>
                            <Stepper.Number>2</Stepper.Number>
                            <Stepper.Title>Development</Stepper.Title>
                        </Stepper.Header>
                        <Stepper.Separator />
                    </Stepper.Step>
                    <Stepper.Step value="3">
                        <Stepper.Header>
                            <Stepper.Number>3</Stepper.Number>
                            <Stepper.Title>QA</Stepper.Title>
                        </Stepper.Header>
                        <Stepper.Separator />
                    </Stepper.Step>
                </Stepper.List>
            </Stepper>
        </div>
    );
}

Template#

The optional as property controls the default container element of a step, for example setting it to a button renders a button for the header instead of a div. The asChild option enables the headless mode for further customization by passing callbacks and properties to implement your own step.

Create your account
import { StepperPanelInstance, StepperStepInstance } from '@primereact/types/shared/stepper';
import Image from 'next/image';
import { Button } from 'primereact/button';
import { Divider } from 'primereact/divider';
import { InputText } from 'primereact/inputtext';
import { Stepper } from 'primereact/stepper';
import { ToggleButton } from 'primereact/togglebutton';
 
export default function TemplateDemo() {
    return (
        <div className="card flex justify-center">
            <Stepper value={1} className="basis-[40rem]">
                <Stepper.List>
                    <Stepper.Step asChild value={1}>
                        {(instance: StepperStepInstance) => {
                            const { stepper, props } = instance;
 
                            return (
                                <div className="flex flex-row flex-auto gap-2">
                                    <button className="bg-transparent border-0 inline-flex flex-col gap-2 cursor-pointer" onClick={() => stepper?.setActiveStep(props.value)}>
                                        <span
                                            className={`rounded-full border-2 w-12 h-12 inline-flex items-center justify-center ${
                                                (instance?.props?.value as number) <= (stepper?.state.value as number) ? 'bg-primary text-primary-contrast border-primary' : 'border-surface-200 dark:border-surface-700'
                                            }`}
                                        >
                                            <i className="pi pi-user" />
                                        </span>
                                    </button>
                                    <Divider />
                                </div>
                            );
                        }}
                    </Stepper.Step>
                    <Stepper.Step asChild value={2}>
                        {(instance: StepperStepInstance) => {
                            const { stepper, props } = instance;
 
                            return (
                                <div className="flex flex-row flex-auto gap-2">
                                    <button className="bg-transparent border-0 inline-flex flex-col gap-2 cursor-pointer" onClick={() => stepper?.setActiveStep(props.value)}>
                                        <span
                                            className={`rounded-full border-2 w-12 h-12 inline-flex items-center justify-center ${
                                                (props?.value as number) <= (stepper?.state.value as number) ? 'bg-primary text-primary-contrast border-primary' : 'border-surface-200 dark:border-surface-700'
                                            }`}
                                        >
                                            <i className="pi pi-star" />
                                        </span>
                                    </button>
                                    <Divider />
                                </div>
                            );
                        }}
                    </Stepper.Step>
                    <Stepper.Step asChild value={3}>
                        {(instance: StepperStepInstance) => {
                            const { stepper, props } = instance;
 
                            return (
                                <div className="flex flex-row gap-2">
                                    <button className="bg-transparent border-0 inline-flex flex-col gap-2 cursor-pointer" onClick={() => stepper?.setActiveStep(props.value)}>
                                        <span
                                            className={`rounded-full border-2 w-12 h-12 inline-flex items-center justify-center ${
                                                (props?.value as number) <= (stepper?.state.value as number) ? 'bg-primary text-primary-contrast border-primary' : 'border-surface-200 dark:border-surface-700'
                                            }`}
                                        >
                                            <i className="pi pi-id-card" />
                                        </span>
                                    </button>
                                </div>
                            );
                        }}
                    </Stepper.Step>
                </Stepper.List>
                <Stepper.Panels>
                    <Stepper.Panel asChild value={1}>
                        {(instance: StepperPanelInstance) => {
                            const { stepper } = instance;
 
                            return (
                                <>
                                    <div className="flex flex-col gap-2 mx-auto" style={{ minHeight: '16rem', maxWidth: '20rem' }}>
                                        <div className="text-center mt-4 mb-4 text-xl font-semibold">Create your account</div>
                                        <div className="field">
                                            <InputText id="input" type="text" placeholder="Name" fluid />
                                        </div>
                                        <div className="field">
                                            <InputText id="email" type="email" placeholder="Email" fluid />
                                        </div>
                                        <div className="field">
                                            <InputText id="password" placeholder="Password" fluid />
                                        </div>
                                    </div>
                                    <div className="flex pt-6 justify-end">
                                        <Button onClick={() => stepper?.setActiveStep(2)}>
                                            Next
                                            <i className="pi pi-arrow-right" />
                                        </Button>
                                    </div>
                                </>
                            );
                        }}
                    </Stepper.Panel>
                    <Stepper.Panel asChild value={2}>
                        {(instance: StepperPanelInstance) => {
                            const { stepper } = instance;
 
                            return (
                                <>
                                    <div className="flex flex-col gap-2 mx-auto" style={{ minHeight: '16rem', maxWidth: '24rem' }}>
                                        <div className="text-center mt-4 mb-4 text-xl font-semibold">Choose your interests</div>
                                        <div className="flex flex-wrap justify-center gap-4">
                                            <ToggleButton>
                                                <ToggleButton.Indicator>Nature</ToggleButton.Indicator>
                                            </ToggleButton>
                                            <ToggleButton>
                                                <ToggleButton.Indicator>Art</ToggleButton.Indicator>
                                            </ToggleButton>
                                            <ToggleButton>
                                                <ToggleButton.Indicator>Music</ToggleButton.Indicator>
                                            </ToggleButton>
                                            <ToggleButton>
                                                <ToggleButton.Indicator>Design</ToggleButton.Indicator>
                                            </ToggleButton>
                                            <ToggleButton>
                                                <ToggleButton.Indicator>Photography</ToggleButton.Indicator>
                                            </ToggleButton>
                                            <ToggleButton>
                                                <ToggleButton.Indicator>Movies</ToggleButton.Indicator>
                                            </ToggleButton>
                                            <ToggleButton>
                                                <ToggleButton.Indicator>Sports</ToggleButton.Indicator>
                                            </ToggleButton>
                                            <ToggleButton>
                                                <ToggleButton.Indicator>Gaming</ToggleButton.Indicator>
                                            </ToggleButton>
                                            <ToggleButton>
                                                <ToggleButton.Indicator>Traveling</ToggleButton.Indicator>
                                            </ToggleButton>
                                            <ToggleButton>
                                                <ToggleButton.Indicator>Dancing</ToggleButton.Indicator>
                                            </ToggleButton>
                                        </div>
                                    </div>
                                    <div className="flex pt-6 justify-between">
                                        <Button severity="secondary" onClick={() => stepper?.setActiveStep(1)}>
                                            <i className="pi pi-arrow-left" />
                                            Back
                                        </Button>
                                        <Button onClick={() => stepper?.setActiveStep(3)}>
                                            Next
                                            <i className="pi pi-arrow-right" />
                                        </Button>
                                    </div>
                                </>
                            );
                        }}
                    </Stepper.Panel>
                    <Stepper.Panel asChild value={3}>
                        {(instance: StepperPanelInstance) => {
                            const { stepper } = instance;
 
                            return (
                                <>
                                    <div className="flex flex-col gap-2 mx-auto" style={{ minHeight: '16rem', maxWidth: '24rem' }}>
                                        <div className="text-center mt-4 mb-4 text-xl font-semibold">Account created successfully</div>
                                        <div className="flex justify-center">
                                            <Image alt="logo" width={240} height={160} src="https://primefaces.org/cdn/primevue/images/stepper/content.svg" />
                                        </div>
                                    </div>
                                    <div className="flex pt-6 justify-start">
                                        <Button severity="secondary" onClick={() => stepper?.setActiveStep(2)}>
                                            <i className="pi pi-arrow-left" />
                                            Back
                                        </Button>
                                    </div>
                                </>
                            );
                        }}
                    </Stepper.Panel>
                </Stepper.Panels>
            </Stepper>
        </div>
    );
}

Accessibility#

Screen Reader#

Stepper container is defined with the tablist role, as any attribute is passed to the container element aria-labelledby can be optionally used to specify an element to describe the Stepper. Each stepper header has a tab role and aria-controls to refer to the corresponding stepper content element. The content element of each stepper has tabpanel role, an id to match the aria-controls of the header and aria-labelledby reference to the header as the accessible name.

Tab Header Keyboard Support#

KeyFunction
tabMoves focus through the header.
enterActivates the focused stepper header.
spaceActivates the focused stepper header.