The Stepper component guides users through a multi-step process, showing progress and allowing navigation between steps.
Basic usage
<flx-stepper [(activeStep)]="currentStep">
<flx-step label="Account" icon="user">
<h3>Create your account</h3>
<!-- Account form content -->
</flx-step>
<flx-step label="Profile" icon="id-card">
<h3>Complete your profile</h3>
<!-- Profile form content -->
</flx-step>
<flx-step label="Preferences" icon="settings">
<h3>Set preferences</h3>
<!-- Preferences content -->
</flx-step>
</flx-stepper>
Stepper properties
Index of the currently active step
orientation
'horizontal' | 'vertical'
default:"horizontal"
Layout direction of the stepper
When true, users must complete steps in order
Allows navigation to completed steps
Step properties
Label displayed for the step
Icon to display in the step indicator
state
'incomplete' | 'active' | 'complete' | 'error'
Current state of the step
Marks the step as optional
Disables navigation to this step
Marks the step as completed
Events
Emitted when the active step changes
Emitted when a step is clicked
Examples
Basic stepper
Linear stepper
Vertical stepper
With icons and states
Optional steps
With validation
<flx-stepper [(activeStep)]="currentStep">
<flx-step label="Personal Info">
<form>
<flx-input label="Name" [(ngModel)]="data.name"></flx-input>
<flx-input label="Email" [(ngModel)]="data.email"></flx-input>
<button (click)="nextStep()">Next</button>
</form>
</flx-step>
<flx-step label="Address">
<form>
<flx-input label="Street" [(ngModel)]="data.street"></flx-input>
<flx-input label="City" [(ngModel)]="data.city"></flx-input>
<button (click)="previousStep()">Back</button>
<button (click)="nextStep()">Next</button>
</form>
</flx-step>
<flx-step label="Review">
<div class="review">
<h4>Review your information</h4>
<p>Name: {{ data.name }}</p>
<p>Email: {{ data.email }}</p>
<p>Address: {{ data.street }}, {{ data.city }}</p>
<button (click)="previousStep()">Back</button>
<button (click)="submit()">Submit</button>
</div>
</flx-step>
</flx-stepper>
export class MultiStepForm {
currentStep = 0;
data = {
name: '',
email: '',
street: '',
city: ''
};
nextStep() {
this.currentStep++;
}
previousStep() {
this.currentStep--;
}
submit() {
console.log('Form submitted:', this.data);
}
}
<flx-stepper
[(activeStep)]="currentStep"
[linear]="true"
[editable]="false">
<flx-step
label="Account"
[completed]="stepCompleted[0]">
<!-- Step 1 content -->
<button (click)="completeStep(0)">Next</button>
</flx-step>
<flx-step
label="Verification"
[completed]="stepCompleted[1]">
<!-- Step 2 content -->
<button (click)="completeStep(1)">Next</button>
</flx-step>
<flx-step label="Complete">
<!-- Final step content -->
</flx-step>
</flx-stepper>
export class LinearStepper {
currentStep = 0;
stepCompleted = [false, false, false];
completeStep(index: number) {
this.stepCompleted[index] = true;
this.currentStep++;
}
}
<flx-stepper
[(activeStep)]="currentStep"
orientation="vertical">
<flx-step label="Choose plan" icon="package">
<div class="plan-selection">
<!-- Plan selection content -->
</div>
</flx-step>
<flx-step label="Payment" icon="credit-card">
<div class="payment-form">
<!-- Payment form -->
</div>
</flx-step>
<flx-step label="Confirmation" icon="check-circle">
<div class="confirmation">
<!-- Confirmation content -->
</div>
</flx-step>
</flx-stepper>
<flx-stepper [(activeStep)]="currentStep">
<flx-step
label="Validation"
icon="shield-check"
[state]="getStepState(0)">
<!-- Content -->
</flx-step>
<flx-step
label="Processing"
icon="loader"
[state]="getStepState(1)">
<!-- Content -->
</flx-step>
<flx-step
label="Complete"
icon="check"
[state]="getStepState(2)">
<!-- Content -->
</flx-step>
</flx-stepper>
export class StepperWithStates {
currentStep = 0;
stepStates = ['complete', 'active', 'incomplete'];
getStepState(index: number): string {
if (index < this.currentStep) return 'complete';
if (index === this.currentStep) return 'active';
return 'incomplete';
}
}
<flx-stepper [(activeStep)]="currentStep">
<flx-step label="Required Info">
<!-- Required content -->
</flx-step>
<flx-step
label="Additional Info"
[optional]="true">
<p class="optional-label">Optional</p>
<!-- Optional content -->
</flx-step>
<flx-step label="Review">
<!-- Review content -->
</flx-step>
</flx-stepper>
<flx-stepper [(activeStep)]="currentStep">
<flx-step
label="Email"
[state]="emailStepState">
<flx-input
type="email"
[(ngModel)]="email"
[error]="emailError">
</flx-input>
<button
(click)="validateAndNext()"
[disabled]="!email">
Next
</button>
</flx-step>
<flx-step label="Password">
<!-- Password step -->
</flx-step>
</flx-stepper>
export class ValidatedStepper {
currentStep = 0;
email = '';
emailError = false;
emailStepState = 'incomplete';
validateAndNext() {
if (this.validateEmail(this.email)) {
this.emailStepState = 'complete';
this.currentStep++;
} else {
this.emailError = true;
this.emailStepState = 'error';
}
}
validateEmail(email: string): boolean {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}
}
Styling
flx-stepper {
--flx-stepper-indicator-size: 32px;
--flx-stepper-indicator-border: 2px;
--flx-stepper-line-thickness: 2px;
--flx-stepper-incomplete-color: #d1d5db;
--flx-stepper-active-color: #3b82f6;
--flx-stepper-complete-color: #10b981;
--flx-stepper-error-color: #ef4444;
--flx-stepper-label-color: #6b7280;
--flx-stepper-active-label-color: #111827;
}
Accessibility
The Stepper component ensures accessibility:
role="tablist" for step headers
role="tab" for individual steps
aria-current="step" for active step
aria-disabled for disabled steps
- Keyboard navigation (Arrow keys, Home, End)
- Screen reader announcements
Best practices
- Use 3-5 steps for optimal user experience
- Provide clear, concise step labels
- Show progress visually with completion indicators
- Enable back navigation unless data loss is a concern
- Use linear mode for processes that must be completed in order
- Mark optional steps clearly
- Validate each step before allowing progression
- Provide clear error states for invalid steps
- Save progress automatically or provide save options
For long forms, use the stepper to break content into manageable sections. Each step should take about 30-60 seconds to complete.
When using linear mode, ensure each step has clear validation and error messaging so users understand why they can’t proceed.