Stepper

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


import { StepperModule } from 'primeng/stepper';

Stepper consists of one or more StepperPanel elements to encapsulate each step in the progress. The elements to navigate between the steps are not built-in for ease of customization, instead prevCallback and nextCallback events should be bound to your custom UI elements.

Content I

<p-stepper>
    <p-stepperPanel header="Header I">
        <ng-template pTemplate="content" let-nextCallback="nextCallback" let-index="index">
            <div class="flex flex-column h-12rem">
                <div class="border-2 border-dashed surface-border border-round surface-ground flex-auto flex justify-content-center align-items-center font-medium">
                    Content I
                </div>
            </div>
            <div class="flex pt-4 justify-content-end">
                <p-button 
                    label="Next" 
                    icon="pi pi-arrow-right" 
                    iconPos="right" 
                    (onClick)="nextCallback.emit()" />
            </div>
        </ng-template>
    </p-stepperPanel>
    <p-stepperPanel header="Header II">
        <ng-template pTemplate="content" let-prevCallback="prevCallback" let-nextCallback="nextCallback" let-index="index">
            <div class="flex flex-column h-12rem">
                <div class="border-2 border-dashed surface-border border-round surface-ground flex-auto flex justify-content-center align-items-center font-medium">
                    Content II
                </div>
            </div>
            <div class="flex pt-4 justify-content-between">
                <p-button 
                    label="Back" 
                    icon="pi pi-arrow-left" 
                    (onClick)="prevCallback.emit()" />
                <p-button 
                    label="Next" 
                    icon="pi pi-arrow-right" 
                    iconPos="right" 
                    (onClick)="nextCallback.emit()" />
            </div>
        </ng-template>
    </p-stepperPanel>
    <p-stepperPanel header="Header III">
        <ng-template pTemplate="content" let-prevCallback="prevCallback" let-index="index">
            <div class="flex flex-column h-12rem">
                <div class="border-2 border-dashed surface-border border-round surface-ground flex-auto flex justify-content-center align-items-center font-medium">
                    Content III
                </div>
            </div>
            <div class="flex pt-4 justify-content-start">
                <p-button label="Back" icon="pi pi-arrow-left" (onClick)="prevCallback.emit()" />
            </div>
        </ng-template>
    </p-stepperPanel>
</p-stepper>

Layout of the Stepper is configured with the orientation property that accepts horizontal and vertical as available options.

1Header I
Content I
2Header II
3Header III

<p-stepper orientation="vertical">
    <p-stepperPanel header="Header I">
        <ng-template pTemplate="content" let-nextCallback="nextCallback" let-index="index">
            <div class="flex flex-column h-12rem">
                <div class="border-2 border-dashed surface-border border-round surface-ground flex-auto flex justify-content-center align-items-center font-medium">Content I</div>
            </div>
            <div class="flex py-4">
                <p-button label="Next" (onClick)="nextCallback.emit()" />
            </div
        ></ng-template>
    </p-stepperPanel>
    <p-stepperPanel header="Header II">
        <ng-template pTemplate="content" let-prevCallback="prevCallback" let-nextCallback="nextCallback" let-index="index">
            <div class="flex flex-column h-12rem">
                <div class="border-2 border-dashed surface-border border-round surface-ground flex-auto flex justify-content-center align-items-center font-medium">
                    Content II
                </div>
            </div>
            <div class="flex py-4 gap-2">
                <p-button label="Back" severity="secondary" (onClick)="prevCallback.emit()" />
                <p-button label="Next" (onClick)="nextCallback.emit()" />
            </div>
        </ng-template>
    </p-stepperPanel>
    <p-stepperPanel header="Header III">
        <ng-template pTemplate="content" let-prevCallback="prevCallback" let-index="index">
            <div class="flex flex-column h-12rem">
                <div class="border-2 border-dashed surface-border border-round surface-ground flex-auto flex justify-content-center align-items-center font-medium">
                    Content III
                </div>
            </div>
            <div class="flex py-4">
                <p-button label="Back" (onClick)="prevCallback.emit()" />
            </div>
        </ng-template>
    </p-stepperPanel>
</p-stepper>

When linear property is present, current step must be completed in order to move to the next step.

Content I

<p-stepper [linear]="true">
    <p-stepperPanel header="Header I">
        <ng-template pTemplate="content" let-nextCallback="nextCallback" let-index="index">
            <div class="flex flex-column h-12rem">
                <div class="border-2 border-dashed surface-border border-round surface-ground flex-auto flex justify-content-center align-items-center font-medium">
                    Content I
                </div>
            </div>
            <div class="flex pt-4 justify-content-end">
                <p-button label="Next" icon="pi pi-arrow-right" iconPos="right" (onClick)="nextCallback.emit()" />
            </div>
        </ng-template>
    </p-stepperPanel>
    <p-stepperPanel header="Header II">
        <ng-template pTemplate="content" let-prevCallback="prevCallback" let-nextCallback="nextCallback" let-index="index">
            <div class="flex flex-column h-12rem">
                <div class="border-2 border-dashed surface-border border-round surface-ground flex-auto flex justify-content-center align-items-center font-medium">
                    Content II
                </div>
            </div>
            <div class="flex pt-4 justify-content-between">
                <p-button label="Back" icon="pi pi-arrow-left" (onClick)="prevCallback.emit()" />
                <p-button label="Next" icon="pi pi-arrow-right" iconPos="right" (onClick)="nextCallback.emit()" />
            </div>
        </ng-template>
    </p-stepperPanel>
    <p-stepperPanel header="Header III">
        <ng-template pTemplate="content" let-prevCallback="prevCallback" let-index="index">
            <div class="flex flex-column h-12rem">
                <div class="border-2 border-dashed surface-border border-round surface-ground flex-auto flex justify-content-center align-items-center font-medium">
                    Content III
                </div>
            </div>
            <div class="flex pt-4 justify-content-start">
                <p-button label="Back" icon="pi pi-arrow-left" (onClick)="prevCallback.emit()" />
            </div>
        </ng-template>
    </p-stepperPanel>
</p-stepper>

Stepper provides various templating options to customize the default UI design.

Create your account

<p-stepper [(activeStep)]="active">
    <p-stepperPanel>
        <ng-template pTemplate="header" let-onClick="onClick" let-index="index">
            <button class="bg-transparent border-none inline-flex flex-column gap-2" (click)="onClick.emit()">
                <span
                    class="border-round border-2 w-3rem h-3rem inline-flex align-items-center justify-content-center"
                    [ngClass]="{
                        'bg-primary border-primary': index <= active,
                        'surface-border': index > active
                    }"
                >
                    <i class="pi pi-user"></i>
                </span>
            </button>
        </ng-template>
        <ng-template pTemplate="content" let-nextCallback="nextCallback">
            <div class="flex flex-column gap-2 mx-auto" style="min-height: 16rem; max-width: 20rem">
                <div class="text-center mt-3 mb-3 text-xl font-semibold">Create your account</div>
                <div class="field p-fluid">
                    <p-iconField>
                        <p-inputIcon>
                            <i class="pi pi-user"></i>
                        </p-inputIcon>
                        <input [(ngModel)]="name" pInputText id="input" type="text" placeholder="Name" />
                    </p-iconField>
                </div>
                <div class="field p-fluid">
                    <p-iconField>
                        <p-inputIcon>
                            <i class="pi pi-envelope"></i>
                        </p-inputIcon>
                        <input [(ngModel)]="email" pInputText id="email" type="email" placeholder="Email" />
                    </p-iconField>
                </div>
                <div class="field p-fluid">
                    <p-password [(ngModel)]="password" [toggleMask]="true" placeholder="Password" />
                </div>
            </div>
            <div class="flex pt-4 justify-content-end">
                <p-button (onClick)="nextCallback.emit()" label="Next" icon="pi pi-arrow-right" iconPos="right" />
            </div>
        </ng-template>
    </p-stepperPanel>
    <p-stepperPanel>
        <ng-template pTemplate="header" let-onClick="onClick" let-index="index">
            <button class="bg-transparent border-none inline-flex flex-column gap-2" (click)="onClick.emit()">
                <span
                    class="border-round border-2 w-3rem h-3rem inline-flex align-items-center justify-content-center"
                    [ngClass]="{
                        'bg-primary border-primary': index <= active,
                        'surface-border': index > active
                    }"
                >
                    <i class="pi pi-star"></i>
                </span>
            </button>
        </ng-template>
        <ng-template pTemplate="content" let-prevCallback="prevCallback" let-nextCallback="nextCallback">
            <div class="flex flex-column gap-2 mx-auto" style="min-height: 16rem; max-width: 24rem">
                <div class="text-center mt-3 mb-3 text-xl font-semibold">Choose your interests</div>
                <div class="flex flex-wrap justify-content-center gap-3">
                    <p-toggleButton [(ngModel)]="option1" onLabel="Nature" offLabel="Nature" />
                    <p-toggleButton [(ngModel)]="option2" onLabel="Art" offLabel="Art" />
                    <p-toggleButton [(ngModel)]="option3" onLabel="Music" offLabel="Music" />
                    <p-toggleButton [(ngModel)]="option4" onLabel="Design" offLabel="Design" />
                    <p-toggleButton [(ngModel)]="option5" onLabel="Photography" offLabel="Photography" />
                    <p-toggleButton [(ngModel)]="option6" onLabel="Movies" offLabel="Movies" />
                    <p-toggleButton [(ngModel)]="option7" onLabel="Sports" offLabel="Sports" />
                    <p-toggleButton [(ngModel)]="option8" onLabel="Gaming" offLabel="Gaming" />
                    <p-toggleButton [(ngModel)]="option9" onLabel="Traveling" offLabel="Traveling" />
                    <p-toggleButton [(ngModel)]="option10" onLabel="Dancing" offLabel="Dancing" />
                </div>
            </div>
            <div class="flex pt-4 justify-content-between">
                <p-button (onClick)="prevCallback.emit()" label="Back" severity="secondary" icon="pi pi-arrow-left" />
                <p-button (onClick)="nextCallback.emit()" label="Next" icon="pi pi-arrow-right" iconPos="right" />
            </div>
        </ng-template>
    </p-stepperPanel>
    <p-stepperPanel>
        <ng-template pTemplate="header" let-onClick="onClick" let-index="index">
            <button class="bg-transparent border-none inline-flex flex-column gap-2" (click)="onClick.emit()">
                <span
                    class="border-round border-2 w-3rem h-3rem inline-flex align-items-center justify-content-center"
                    [ngClass]="{
                        'bg-primary border-primary': index <= active,
                        'surface-border': index > active
                    }"
                >
                    <i class="pi pi-id-card"></i>
                </span>
            </button>
        </ng-template>
        <ng-template pTemplate="content" let-prevCallback="prevCallback">
            <div class="flex flex-column gap-2 mx-auto" style="min-height: 16rem; max-width: 24rem">
                <div class="text-center mt-3 mb-3 text-xl font-semibold">Account created successfully</div>
                <div class="text-center">
                    <img alt="logo" src="https://primefaces.org/cdn/primeng/images/stepper/content.svg" />
                </div>
            </div>
            <div class="flex pt-4 justify-content-start">
                <p-button (onClick)="prevCallback.emit()" label="Back" severity="secondary" icon="pi pi-arrow-left" />
            </div>
        </ng-template>
    </p-stepperPanel>
</p-stepper>

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.