
Syncfusion Angular Stepper
- 158 installs
- Updated August 4, 2026
- syncfusion/angular-ui-components-skills
Use syncfusion-angular-stepper for development tasks
About
syncfusion-angular-stepper: A skill for development. This provides functionality for development workflows.
- syncfusion-angular-stepper
Syncfusion Angular Stepper by the numbers
- 158 all-time installs (skills.sh)
- +5 installs in the week ending Jul 27, 2026 (Skillselion tracking)
- Ranked #2,367 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/syncfusion/angular-ui-components-skills --skill syncfusion-angular-stepperAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 158 |
|---|---|
| Last updated | August 4, 2026 |
| Repository | syncfusion/angular-ui-components-skills ↗ |
What it does
Use syncfusion-angular-stepper for development tasks
Files
Implementing Syncfusion Angular Stepper
The Syncfusion Angular Stepper component displays a step-by-step process or workflow, ideal for wizards, onboarding, or multi-step forms. This skill guides you through implementing, configuring, and customizing the Stepper component with complete control over step appearance, validation, events, and animations.
When to Use This Skill
Use this skill when:
- Building multi-step wizards or workflows
- Creating step-by-step forms or onboarding flows
- Configuring step validation and linear flow
- Adding icons, labels, and custom templates to steps
- Handling step events (created, stepChanged, stepChanging, beforeStepRender, stepClick)
- Customizing step appearance with animations and styling
- Implementing tooltips, globalization, or RTL support
Component Overview
The Stepper component provides:
- Multiple step types: Default (icons + labels), Indicator Only, Label Only
- Two orientations: Horizontal (default) and Vertical
- Rich event system: created, stepChanged, stepChanging, beforeStepRender, stepClick
- Step validation: Linear flow, completion states, conditional progression
- Customization: Icons, labels, templates, animations, tooltips
- Accessibility: WCAG compliance, keyboard navigation, RTL support
Complete Table of Contents
🚀 Getting Started
📄 Read: references/getting-started.md
- Installation and package configuration
- Angular CLI setup and dependencies
- Basic stepper implementation in standalone Angular
- CSS imports and theme setup
- First render and initial configuration
📋 API Reference
📄 Read: references/api-reference.md
- Stepper Component Properties:
activeStep,animation,cssClass,enablePersistence,enableRtl,labelPosition,linear,locale,orientation,readOnly,showTooltip,stepType,steps,template,tooltipTemplate - Step Model Properties:
cssClass,disabled,iconCss,isValid,label,optional,status,text - Animation Settings:
enable,duration,delay - Stepper Methods:
destroy(),nextStep(),previousStep(),refreshProgressbar(),reset() - Events Overview:
created,stepChanged,stepChanging,stepClick,beforeStepRender - Enumerations:
StepType,StepStatus,StepLabelPosition,StepperOrientation
⚙️ Configuring Steps
📄 Read: references/steps-configuration.md
- Adding steps with
<e-step>directive - Configuring icons with
iconCssproperty - Setting labels and text content
- Setting active step with
activeStep - Optional steps and disabling steps
- Step read-only mode
- Step status tracking
- Step validation with
isValidproperty - Label positioning and alignment
🎨 Choosing Step Types
📄 Read: references/step-types.md
- Default type with indicators and labels
- Indicator Only type for compact layouts
- Label Only type for text-based navigation
- Label positions (Top, Bottom, Start, End)
- When to use each type
- Type selection patterns
📐 Setting Orientations
📄 Read: references/orientations-and-layouts.md
- Horizontal orientation (default)
- Vertical orientation for tall layouts
- Layout configuration and responsive design
- Orientation selection based on use case
🎯 Handling Events & Interactions
📄 Read: references/events-and-interactions.md
createdevent for initializationstepChangedevent after step changes (with EventArgs)stepChangingevent for step change prevention (with EventArgs)beforeStepRenderevent for pre-render customization (with EventArgs)stepClickevent for click handling (with EventArgs)- Complete EventArgs reference documentation
- Event handler patterns and best practices
✅ Validation and Flow Control
📄 Read: references/validation-and-flow.md
- Linear flow configuration for sequential progression
- Step validation and completion states
- Step status management
- Conditional step progression
- Error handling and state management
🎭 Templates and Styling
📄 Read: references/templates-and-customization.md
- Custom step templates using
<ng-template> - Template binding and data context
- CSS class customization (
cssClassproperty) - Layout and appearance customization
- Responsive styling patterns
🌟 Advanced Features
📄 Read: references/advanced-features.md
- Animation settings (duration, delay, enable) with StepperAnimationSettingsModel
- Tooltip configuration and tooltip templates
- Globalization and localization (i18n)
- RTL (Right-to-Left) support with
enableRtl - Accessibility features and keyboard navigation
- WCAG compliance and screen reader support
Quick Start Example
import { Component } from "@angular/core";
import { StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<div class="stepper-container">
<ejs-stepper>
<e-steps>
<e-step label="Cart" iconCss="sf-icon-cart"></e-step>
<e-step label="Delivery Address" iconCss="sf-icon-transport"></e-step>
<e-step label="Payment" iconCss="sf-icon-payment"></e-step>
<e-step label="Confirmation" iconCss="sf-icon-success"></e-step>
</e-steps>
</ejs-stepper>
</div>
`,
styles: [`
.stepper-container {
padding: 20px;
max-width: 800px;
margin: 0 auto;
}
`]
})
export class AppComponent { }Common Patterns
Pattern 1: Wizard with Form Validation
<ejs-stepper (stepChanging)="onStepChanging($event)">
<e-steps>
<e-step label="Personal Info"></e-step>
<e-step label="Contact Details"></e-step>
<e-step label="Address"></e-step>
<e-step label="Confirmation"></e-step>
</e-steps>
</ejs-stepper>Use the stepChanging event to validate form data before allowing step progression.
Pattern 2: Dynamic Step Icons
<ejs-stepper>
<e-steps>
<e-step *ngFor="let step of steps"
[label]="step.label"
[iconCss]="step.icon"></e-step>
</e-steps>
</ejs-stepper>Bind step data dynamically using *ngFor directive.
Pattern 3: Linear Workflow
<ejs-stepper [linear]="true">
<e-steps>
<e-step label="Step 1"></e-step>
<e-step label="Step 2"></e-step>
<e-step label="Step 3"></e-step>
</e-steps>
</ejs-stepper>Enable linear property to enforce sequential progression.
Pattern 4: Event Handling
onStepChanged(args: StepperChangedEventArgs) {
console.log(`Active step index: ${args.activeStep}`);
}
onStepChanging(args: StepperChangingEventArgs) {
if (!isFormValid()) {
args.cancel = true; // Prevent step change
}
}Use event handlers to track navigation and validate progress.
Key Properties Summary
| Property | Type | Default | When to Use |
|---|---|---|---|
stepType | StepType | Default | Change display style: Default, Indicator, Label |
orientation | Orientation | Horizontal | Set layout: Horizontal or Vertical |
linear | boolean | false | Enforce sequential progression |
activeStep | number | 0 | Set current active step (0-indexed) |
animation | StepperAnimationSettingsModel | enabled | Configure transition animations |
showTooltip | boolean | false | Display tooltips on step hover |
labelPosition | string | Bottom | Position labels: Top, Bottom, Start, End |
readOnly | boolean | false | Disable all step interactions |
cssClass | string | - | Apply custom CSS classes |
enableRtl | boolean | false | Enable RTL for Arabic, Hebrew, Urdu |
enablePersistence | boolean | false | Persist state between page reloads |
locale | string | en-US | Set language/culture |
For complete API reference with code examples, see: 📚 API Reference
Common Use Cases
Wizard Forms: Implement multi-step form wizards with validation at each step Onboarding Flow: Guide new users through setup or introduction steps Process Tracking: Display workflow progress (order processing, job applications) Multi-Step Checkout: Create shopping cart workflows with address and payment steps Setup Assistants: Configure tools or services through guided step-by-step setup Document Submission: Multi-step document upload with validation
---
Next Steps: Select a reference above based on what you need to implement. Start with getting-started.md if this is your first time using the Stepper component.
Advanced Features in Angular Stepper
Table of Contents
Animation Settings
The Angular Stepper component supports smooth animations during step transitions. Configure animations using the animation property with StepperAnimationSettingsModel.
See also: API Reference - Animation Settings | API Reference - StepperAnimationSettingsModel
Animation Configuration
import { Component } from "@angular/core";
import { StepperAllModule, StepperModule, StepperAnimationSettingsModel } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<div class="animation-example">
<div class="controls">
<button (click)="toggleAnimation()">
{{ animationEnabled ? 'Disable' : 'Enable' }} Animation
</button>
<span>Duration: {{ animationDuration }}ms | Delay: {{ animationDelay }}ms</span>
</div>
<ejs-stepper [animation]="animationSettings">
<e-steps>
<e-step label="Step 1" iconCss="sf-icon-home"></e-step>
<e-step label="Step 2" iconCss="sf-icon-settings"></e-step>
<e-step label="Step 3" iconCss="sf-icon-database"></e-step>
<e-step label="Step 4" iconCss="sf-icon-check"></e-step>
</e-steps>
</ejs-stepper>
</div>
`,
styles: [`
.animation-example {
padding: 20px;
max-width: 700px;
margin: 0 auto;
}
.controls {
margin-bottom: 20px;
padding: 10px;
background-color: #f5f5f5;
border-radius: 4px;
display: flex;
gap: 10px;
align-items: center;
}
button {
padding: 8px 16px;
background-color: #1976d2;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
`]
})
export class AppComponent {
animationEnabled = true;
animationDuration = 2000; // milliseconds
animationDelay = 0; // milliseconds
animationSettings: StepperAnimationSettingsModel = {
enable: true,
duration: 2000,
delay: 0
};
toggleAnimation(): void {
this.animationEnabled = !this.animationEnabled;
this.animationSettings.enable = this.animationEnabled;
}
}Animation Properties
| Property | Type | Default | Description |
|---|---|---|---|
enable | boolean | true | Enable/disable animations |
duration | number | 2000 | Animation duration in milliseconds |
delay | number | 0 | Delay before animation starts (ms) |
Animation Examples
Fast Animation (500ms):
animationSettings: StepperAnimationSettingsModel = {
enable: true,
duration: 500,
delay: 0
};Slow Animation with Delay (3000ms + 200ms delay):
animationSettings: StepperAnimationSettingsModel = {
enable: true,
duration: 3000,
delay: 200
};No Animation:
animationSettings: StepperAnimationSettingsModel = {
enable: false
};Tooltips
Display helpful tooltips when users hover over step indicators or labels.
See also: API Reference - showTooltip | API Reference - tooltipTemplate
Enable Tooltips
import { Component } from "@angular/core";
import { StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<div class="tooltip-example">
<ejs-stepper [showTooltip]="true">
<e-steps>
<e-step label="Cart"
iconCss="sf-icon-cart"
text="Review your items"></e-step>
<e-step label="Delivery"
iconCss="sf-icon-transport"
text="Enter shipping address"></e-step>
<e-step label="Payment"
iconCss="sf-icon-payment"
text="Complete payment"></e-step>
<e-step label="Confirmation"
iconCss="sf-icon-success"
text="Order confirmed"></e-step>
</e-steps>
</ejs-stepper>
<p class="instruction">Hover over steps to see tooltips</p>
</div>
`,
styles: [`
.tooltip-example {
padding: 20px;
max-width: 700px;
margin: 0 auto;
}
.instruction {
margin-top: 20px;
color: #666;
font-size: 14px;
}
`]
})
export class AppComponent { }Tooltip with Templates
Create custom tooltip templates:
@Component({
imports: [ StepperAllModule, StepperModule, CommonModule ],
standalone: true,
template: `
<ejs-stepper [showTooltip]="true">
<e-steps>
<e-step label="Step 1" iconCss="sf-icon-1">
<ng-template #stepTooltip>
<div class="custom-tooltip">
<strong>Step 1: Getting Started</strong>
<p>This is the first step in the process</p>
<ul>
<li>Install dependencies</li>
<li>Configure project</li>
</ul>
</div>
</ng-template>
</e-step>
</e-steps>
</ejs-stepper>
`,
styles: [`
.custom-tooltip {
padding: 10px;
}
.custom-tooltip strong {
display: block;
margin-bottom: 5px;
}
`]
})
export class AppComponent { }Tooltip Configuration
| Property | Type | Default | Description |
|---|---|---|---|
showTooltip | boolean | false | Enable/disable tooltips |
Globalization and Localization
Support multiple languages and cultural settings in your Stepper.
See also: API Reference - locale
Localization Example
import { Component } from "@angular/core";
import { StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<div class="localization-example">
<div class="language-selector">
<button (click)="setLanguage('en')">English</button>
<button (click)="setLanguage('es')">Español</button>
<button (click)="setLanguage('fr')">Français</button>
<button (click)="setLanguage('de')">Deutsch</button>
</div>
<ejs-stepper>
<e-steps>
<e-step [label]="translations[currentLanguage].step1"></e-step>
<e-step [label]="translations[currentLanguage].step2"></e-step>
<e-step [label]="translations[currentLanguage].step3"></e-step>
<e-step [label]="translations[currentLanguage].step4"></e-step>
</e-steps>
</ejs-stepper>
</div>
`,
styles: [`
.localization-example {
padding: 20px;
}
.language-selector {
margin-bottom: 20px;
display: flex;
gap: 10px;
}
button {
padding: 8px 12px;
background-color: #1976d2;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
`]
})
export class AppComponent {
currentLanguage = 'en';
translations: any = {
en: {
step1: 'Cart',
step2: 'Delivery Address',
step3: 'Payment',
step4: 'Confirmation'
},
es: {
step1: 'Carrito',
step2: 'Dirección de Entrega',
step3: 'Pago',
step4: 'Confirmación'
},
fr: {
step1: 'Panier',
step2: 'Adresse de Livraison',
step3: 'Paiement',
step4: 'Confirmation'
},
de: {
step1: 'Wagen',
step2: 'Lieferadresse',
step3: 'Zahlung',
step4: 'Bestätigung'
}
};
setLanguage(lang: string): void {
this.currentLanguage = lang;
}
}Best Practices for Localization
1. Use language codes: Follow standards like en, es, fr 2. Right-to-left languages: Set RTL for Arabic, Hebrew, Urdu 3. Date/number formats: Adapt formatting to locale 4. Testing: Test with actual language speakers 5. Resource files: Store translations in separate files
RTL Support
Enable Right-to-Left (RTL) support for languages like Arabic, Hebrew, and Urdu.
See also: API Reference - enableRtl
Enable RTL
import { Component } from "@angular/core";
import { StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<div [attr.dir]="isRTL ? 'rtl' : 'ltr'" class="rtl-example">
<button (click)="toggleRTL()">
{{ isRTL ? 'Switch to LTR' : 'Switch to RTL' }}
</button>
<ejs-stepper [enableRtl]="isRTL">
<e-steps>
<e-step label="الخطوة الأولى" iconCss="sf-icon-cart"></e-step>
<e-step label="الخطوة الثانية" iconCss="sf-icon-transport"></e-step>
<e-step label="الخطوة الثالثة" iconCss="sf-icon-payment"></e-step>
<e-step label="الخطوة الرابعة" iconCss="sf-icon-success"></e-step>
</e-steps>
</ejs-stepper>
</div>
`,
styles: [`
.rtl-example {
padding: 20px;
max-width: 700px;
margin: 0 auto;
}
`]
})
export class AppComponent {
isRTL = false;
toggleRTL(): void {
this.isRTL = !this.isRTL;
}
}RTL CSS
/* RTL specific styling */
[dir="rtl"] :deep(.e-stepper) {
flex-direction: row-reverse;
}
[dir="rtl"] :deep(.e-step-label-container) {
text-align: right;
}
[dir="rtl"] :deep(.e-stepper-progressbar) {
transform: scaleX(-1);
}RTL Localization Example
@Component({
template: `
<div [attr.dir]="language.dir">
<ejs-stepper [enableRtl]="language.dir === 'rtl'">
<e-steps>
<e-step [label]="currentLanguageLabels[0]"></e-step>
<e-step [label]="currentLanguageLabels[1]"></e-step>
<e-step [label]="currentLanguageLabels[2]"></e-step>
</e-steps>
</ejs-stepper>
</div>
`
})
export class AppComponent {
language = { code: 'ar', dir: 'rtl' }; // Arabic with RTL
languages = {
en: { label: 'English', dir: 'ltr' },
ar: { label: 'العربية', dir: 'rtl' },
he: { label: 'עברית', dir: 'rtl' },
ur: { label: 'اردو', dir: 'rtl' }
};
currentLanguageLabels = ['الخطوة الأولى', 'الخطوة الثانية', 'الخطوة الثالثة'];
}Accessibility
Ensure your Stepper is accessible to all users, including those using assistive technologies.
Related: WCAG compliance, keyboard navigation, screen reader support
WCAG Compliance
import { Component } from "@angular/core";
import { StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<div class="accessible-stepper">
<h1>Form Completion</h1>
<ejs-stepper role="navigation"
[attr.aria-label]="'4-step form navigation'">
<e-steps>
<e-step label="Personal Info"
iconCss="sf-icon-profile"
title="Personal Information"></e-step>
<e-step label="Address"
iconCss="sf-icon-location"
title="Delivery Address"></e-step>
<e-step label="Payment"
iconCss="sf-icon-payment"
title="Payment Method"></e-step>
<e-step label="Review"
iconCss="sf-icon-check"
title="Review and Confirmation"></e-step>
</e-steps>
</ejs-stepper>
<!-- Update main content region on step change -->
<main [attr.aria-live]="'polite'" [attr.aria-label]="'Step content'">
<div role="region">
<!-- Step content here -->
</div>
</main>
</div>
`,
styles: [`
.accessible-stepper {
padding: 20px;
max-width: 700px;
margin: 0 auto;
}
`]
})
export class AppComponent { }Accessibility Best Practices
1. ARIA labels: Add aria-label and aria-live attributes 2. Keyboard navigation: Support Tab key to reach steps 3. Focus indicators: Ensure visible focus for keyboard users 4. Color contrast: Maintain WCAG AA color contrast ratios 5. Screen readers: Test with screen readers (NVDA, JAWS) 6. Title attributes: Provide titles for hover information 7. Semantic HTML: Use proper heading hierarchy
Keyboard Navigation Support
<ejs-stepper [attr.tabindex]="'0'"
(keydown)="handleKeydown($event)">
<e-steps>
<e-step label="Step 1"></e-step>
<e-step label="Step 2"></e-step>
<e-step label="Step 3"></e-step>
</e-steps>
</ejs-stepper>handleKeydown(event: KeyboardEvent): void {
if (event.key === 'ArrowRight') {
// Move to next step
} else if (event.key === 'ArrowLeft') {
// Move to previous step
}
}Best Practices Summary
1. Animation: Keep animations smooth but not distracting (500-2000ms) 2. Tooltips: Use for additional context, not redundant info 3. Localization: Plan for multi-language support from the start 4. RTL: Test thoroughly with RTL languages 5. Accessibility: Always include ARIA labels and keyboard support 6. Performance: Disable animations on low-end devices if needed
See also: events-and-interactions.md for event handling, templates-and-customization.md for custom layouts.
API Reference for Angular Stepper
This comprehensive API reference documents all properties, methods, and events available in the Syncfusion Angular Stepper component.
Table of Contents
- Stepper Component Properties
- Step Model Properties
- Animation Settings
- Stepper Methods
- Events and Event Arguments
- Enumerations
---
Stepper Component Properties
activeStep
Type: number Default: 0 Description: Defines the current step index of the Stepper (zero-indexed).
import { Component } from "@angular/core";
import { StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<ejs-stepper activeStep="2">
<e-steps>
<e-step label="Step 1"></e-step>
<e-step label="Step 2"></e-step>
<e-step label="Step 3"></e-step>
<e-step label="Step 4"></e-step>
</e-steps>
</ejs-stepper>
`
})
export class AppComponent { }animation
Type: StepperAnimationSettingsModel Default: { enable: true, duration: 2000, delay: 0 } Description: Defines the step progress animation settings.
import { Component } from "@angular/core";
import { StepperAllModule, StepperModule, StepperAnimationSettingsModel } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<ejs-stepper [animation]="animationSettings">
<e-steps>
<e-step label="Step 1"></e-step>
<e-step label="Step 2"></e-step>
</e-steps>
</ejs-stepper>
`
})
export class AppComponent {
animationSettings: StepperAnimationSettingsModel = {
enable: true,
duration: 2000,
delay: 500
};
}See also: Animation Settings | advanced-features.md
cssClass
Type: string Default: - Description: Defines CSS class(es) to customize the Stepper appearance.
@Component({
template: `
<ejs-stepper cssClass="custom-stepper">
<e-steps>
<e-step label="Step 1"></e-step>
<e-step label="Step 2"></e-step>
</e-steps>
</ejs-stepper>
`,
styles: [`
.custom-stepper :deep(.e-step-container) {
background-color: #f0f0f0;
}
`]
})
export class AppComponent { }enablePersistence
Type: boolean Default: false Description: Enable or disable persisting component's state between page reloads.
@Component({
template: `
<ejs-stepper enablePersistence="true">
<e-steps>
<e-step label="Step 1"></e-step>
<e-step label="Step 2"></e-step>
</e-steps>
</ejs-stepper>
`
})
export class AppComponent { }enableRtl
Type: boolean Default: false Description: Enable or disable rendering component in right-to-left direction.
@Component({
template: `
<ejs-stepper [enableRtl]="true">
<e-steps>
<e-step label="خطوة 1" iconCss="sf-icon-cart"></e-step>
<e-step label="خطوة 2" iconCss="sf-icon-payment"></e-step>
</e-steps>
</ejs-stepper>
`
})
export class AppComponent { }See also: advanced-features.md
labelPosition
Type: string | StepLabelPosition Default: Bottom Description: Defines the label position in the Stepper. Possible values: Top, Bottom, Start, End.
import { Component, ViewChild } from "@angular/core";
import { StepperComponent, StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<div>
<div style="margin-bottom: 20px;">
<label>Label Position: </label>
<select (change)="changeLabelPosition($event)">
<option value="Top">Top</option>
<option value="Bottom">Bottom</option>
<option value="Start">Start</option>
<option value="End">End</option>
</select>
</div>
<ejs-stepper #stepper [labelPosition]="currentPosition">
<e-steps>
<e-step label="Cart" iconCss="sf-icon-cart"></e-step>
<e-step label="Delivery" iconCss="sf-icon-transport"></e-step>
<e-step label="Payment" iconCss="sf-icon-payment"></e-step>
</e-steps>
</ejs-stepper>
</div>
`
})
export class AppComponent {
@ViewChild('stepper') stepper!: StepperComponent;
currentPosition: string = 'Bottom';
changeLabelPosition(event: any): void {
this.currentPosition = event.target.value;
}
}linear
Type: boolean Default: false Description: Defines whether users must complete steps sequentially or can skip to any step.
@Component({
template: `
<ejs-stepper [linear]="true">
<e-steps>
<e-step label="Personal Info"></e-step>
<e-step label="Address"></e-step>
<e-step label="Payment"></e-step>
<e-step label="Confirmation"></e-step>
</e-steps>
</ejs-stepper>
`
})
export class AppComponent { }See also: validation-and-flow.md
locale
Type: string Default: en-US Description: Overrides the global culture and localization value for this component.
@Component({
template: `
<ejs-stepper locale="es">
<e-steps>
<e-step label="Paso 1"></e-step>
<e-step label="Paso 2"></e-step>
</e-steps>
</ejs-stepper>
`
})
export class AppComponent { }See also: advanced-features.md
orientation
Type: string | StepperOrientation Default: Horizontal Description: Defines the orientation type of the Stepper. Possible values: Horizontal, Vertical.
import { Component } from "@angular/core";
import { StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<div style="display: flex; gap: 40px;">
<div style="flex: 1;">
<h3>Horizontal</h3>
<ejs-stepper orientation="Horizontal">
<e-steps>
<e-step label="Step 1"></e-step>
<e-step label="Step 2"></e-step>
<e-step label="Step 3"></e-step>
</e-steps>
</ejs-stepper>
</div>
<div style="flex: 1;">
<h3>Vertical</h3>
<ejs-stepper orientation="Vertical">
<e-steps>
<e-step label="Step 1"></e-step>
<e-step label="Step 2"></e-step>
<e-step label="Step 3"></e-step>
</e-steps>
</ejs-stepper>
</div>
</div>
`
})
export class AppComponent { }See also: orientations-and-layouts.md
readOnly
Type: boolean Default: false Description: Defines whether the read-only mode is enabled, preventing user interaction with the Stepper.
@Component({
template: `
<ejs-stepper readOnly="true">
<e-steps>
<e-step label="Step 1 - Completed"></e-step>
<e-step label="Step 2 - Completed"></e-step>
<e-step label="Step 3 - Completed"></e-step>
</e-steps>
</ejs-stepper>
`
})
export class AppComponent { }showTooltip
Type: boolean Default: false Description: Defines whether to show tooltip on each step when hovering.
@Component({
template: `
<ejs-stepper [showTooltip]="true">
<e-steps>
<e-step label="Cart" text="Review items"></e-step>
<e-step label="Delivery" text="Enter address"></e-step>
<e-step label="Payment" text="Complete payment"></e-step>
</e-steps>
</ejs-stepper>
`
})
export class AppComponent { }See also: advanced-features.md
stepType
Type: string | StepType Default: Default Description: Defines step display style. Possible values: Default (icons with labels), Label (labels only), Indicator (icons/numbers only).
import { Component } from "@angular/core";
import { StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<div style="display: flex; flex-direction: column; gap: 40px;">
<div>
<h3>Default (Icons + Labels)</h3>
<ejs-stepper stepType="Default">
<e-steps>
<e-step label="Cart" iconCss="sf-icon-cart"></e-step>
<e-step label="Payment" iconCss="sf-icon-payment"></e-step>
</e-steps>
</ejs-stepper>
</div>
<div>
<h3>Label Only</h3>
<ejs-stepper stepType="Label">
<e-steps>
<e-step label="Cart"></e-step>
<e-step label="Payment"></e-step>
</e-steps>
</ejs-stepper>
</div>
<div>
<h3>Indicator Only</h3>
<ejs-stepper stepType="Indicator">
<e-steps>
<e-step iconCss="sf-icon-cart"></e-step>
<e-step iconCss="sf-icon-payment"></e-step>
</e-steps>
</ejs-stepper>
</div>
</div>
`
})
export class AppComponent { }See also: step-types.md
steps
Type: StepModel[] Default: - Description: Defines the list of steps in the Stepper.
import { Component } from "@angular/core";
import { StepModel, StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<ejs-stepper [steps]="steps">
</ejs-stepper>
`
})
export class AppComponent {
steps: StepModel[] = [
{ label: 'Cart', iconCss: 'sf-icon-cart' },
{ label: 'Delivery', iconCss: 'sf-icon-transport' },
{ label: 'Payment', iconCss: 'sf-icon-payment' },
{ label: 'Confirmation', iconCss: 'sf-icon-success' }
];
}template
Type: string | object Default: - Description: Defines custom template content for the stepper. Can be used for custom step rendering.
@Component({
template: `
<ejs-stepper [template]="'<span>${text}</span>'">
<e-steps>
<e-step label="Step 1" text="Getting Started"></e-step>
<e-step label="Step 2" text="Configuration"></e-step>
</e-steps>
</ejs-stepper>
`
})
export class AppComponent { }See also: templates-and-customization.md
tooltipTemplate
Type: string | object Default: - Description: Defines custom template content for the tooltip displayed on step hover.
@Component({
template: `
<ejs-stepper [showTooltip]="true" [tooltipTemplate]="tooltipTemplate">
<e-steps>
<e-step label="Step 1"></e-step>
</e-steps>
</ejs-stepper>
`
})
export class AppComponent {
tooltipTemplate: any = '<div>Custom Tooltip</div>';
}---
Step Model Properties
cssClass
Type: string Default: - Description: Defines CSS class(es) to customize individual step appearance.
@Component({
template: `
<ejs-stepper>
<e-steps>
<e-step label="Completed" cssClass="completed-step"></e-step>
<e-step label="Active" cssClass="active-step"></e-step>
<e-step label="Disabled" cssClass="disabled-step"></e-step>
</e-steps>
</ejs-stepper>
`,
styles: [`
:deep(.completed-step) {
color: green;
font-weight: bold;
}
:deep(.active-step) {
color: blue;
}
:deep(.disabled-step) {
opacity: 0.5;
}
`]
})
export class AppComponent { }disabled
Type: boolean Default: false Description: Defines whether a step is disabled and cannot be clicked.
@Component({
template: `
<ejs-stepper>
<e-steps>
<e-step label="Enabled" iconCss="sf-icon-cart"></e-step>
<e-step label="Disabled" iconCss="sf-icon-payment" disabled="true"></e-step>
<e-step label="Enabled" iconCss="sf-icon-success"></e-step>
</e-steps>
</ejs-stepper>
`
})
export class AppComponent { }See also: steps-configuration.md
iconCss
Type: string Default: - Description: Defines the icon CSS class for the step indicator.
@Component({
template: `
<ejs-stepper>
<e-steps>
<e-step iconCss="sf-icon-cart"></e-step>
<e-step iconCss="sf-icon-transport"></e-step>
<e-step iconCss="sf-icon-payment"></e-step>
<e-step iconCss="sf-icon-success"></e-step>
</e-steps>
</ejs-stepper>
`
})
export class AppComponent { }isValid
Type: boolean | null Default: null Description: Defines the validation state. true shows success, false shows error, null shows no validation icon.
@Component({
template: `
<ejs-stepper>
<e-steps>
<e-step label="Valid" [isValid]="true"></e-step>
<e-step label="Invalid" [isValid]="false"></e-step>
<e-step label="Not Validated"></e-step>
</e-steps>
</ejs-stepper>
`
})
export class AppComponent { }See also: validation-and-flow.md
label
Type: string Default: - Description: Defines the text label displayed for the step.
@Component({
template: `
<ejs-stepper>
<e-steps>
<e-step label="Personal Information"></e-step>
<e-step label="Delivery Address"></e-step>
<e-step label="Payment Method"></e-step>
<e-step label="Order Confirmation"></e-step>
</e-steps>
</ejs-stepper>
`
})
export class AppComponent { }optional
Type: boolean Default: false Description: Defines whether the step is optional and can be skipped.
@Component({
template: `
<ejs-stepper>
<e-steps>
<e-step label="Shipping" iconCss="sf-icon-transport"></e-step>
<e-step label="Gift Options" iconCss="sf-icon-gift" optional="true"></e-step>
<e-step label="Payment" iconCss="sf-icon-payment"></e-step>
</e-steps>
</ejs-stepper>
`
})
export class AppComponent { }See also: steps-configuration.md
status
Type: string | StepStatus Default: NotStarted Description: Defines the progress status of the step. Possible values: NotStarted, InProgress, Completed.
import { Component } from "@angular/core";
import { StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<ejs-stepper>
<e-steps>
<e-step label="Step 1" status="Completed"></e-step>
<e-step label="Step 2" status="InProgress"></e-step>
<e-step label="Step 3" status="NotStarted"></e-step>
</e-steps>
</ejs-stepper>
`
})
export class AppComponent { }See also: validation-and-flow.md
text
Type: string Default: - Description: Defines additional text content for the step (used with Indicator step type).
@Component({
template: `
<ejs-stepper stepType="Indicator">
<e-steps>
<e-step text="A"></e-step>
<e-step text="B"></e-step>
<e-step text="C"></e-step>
<e-step text="D"></e-step>
</e-steps>
</ejs-stepper>
`
})
export class AppComponent { }---
Animation Settings
StepperAnimationSettingsModel
Description: Configures animation behavior for step transitions.
enable
Type: boolean Default: true Description: Enable or disable animations.
duration
Type: number Default: 2000 Description: Animation duration in milliseconds.
delay
Type: number Default: 0 Description: Delay before animation starts, in milliseconds.
import { Component } from "@angular/core";
import { StepperAllModule, StepperModule, StepperAnimationSettingsModel } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<ejs-stepper [animation]="animationSettings">
<e-steps>
<e-step label="Step 1"></e-step>
<e-step label="Step 2"></e-step>
<e-step label="Step 3"></e-step>
</e-steps>
</ejs-stepper>
`
})
export class AppComponent {
animationSettings: StepperAnimationSettingsModel = {
enable: true,
duration: 1500,
delay: 100
};
}See also: advanced-features.md
---
Stepper Methods
destroy()
Returns: void Description: Destroys the Stepper control and removes it from the DOM.
import { Component, ViewChild } from "@angular/core";
import { StepperComponent, StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<button (click)="destroyStepper()">Destroy Stepper</button>
<ejs-stepper #stepper>
<e-steps>
<e-step label="Step 1"></e-step>
<e-step label="Step 2"></e-step>
</e-steps>
</ejs-stepper>
`
})
export class AppComponent {
@ViewChild('stepper') stepper!: StepperComponent;
destroyStepper(): void {
this.stepper.destroy();
}
}nextStep()
Returns: void Description: Moves to the next step from the current step in the Stepper.
import { Component, ViewChild } from "@angular/core";
import { StepperComponent, StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<div>
<button (click)="goToNext()">Next Step</button>
<p>Current Step: {{ currentStep }}</p>
<ejs-stepper #stepper (stepChanged)="onStepChanged($event)">
<e-steps>
<e-step label="Step 1"></e-step>
<e-step label="Step 2"></e-step>
<e-step label="Step 3"></e-step>
<e-step label="Step 4"></e-step>
</e-steps>
</ejs-stepper>
</div>
`
})
export class AppComponent {
@ViewChild('stepper') stepper!: StepperComponent;
currentStep = 0;
goToNext(): void {
this.stepper.nextStep();
}
onStepChanged(args: any): void {
this.currentStep = args.activeStep;
}
}previousStep()
Returns: void Description: Moves to the previous step from the current step in the Stepper.
import { Component, ViewChild } from "@angular/core";
import { StepperComponent, StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<div>
<button (click)="goToPrevious()">Previous Step</button>
<p>Current Step: {{ currentStep }}</p>
<ejs-stepper #stepper (stepChanged)="onStepChanged($event)">
<e-steps>
<e-step label="Step 1"></e-step>
<e-step label="Step 2"></e-step>
<e-step label="Step 3"></e-step>
<e-step label="Step 4"></e-step>
</e-steps>
</ejs-stepper>
</div>
`
})
export class AppComponent {
@ViewChild('stepper') stepper!: StepperComponent;
currentStep = 0;
goToPrevious(): void {
this.stepper.previousStep();
}
onStepChanged(args: any): void {
this.currentStep = args.activeStep;
}
}refreshProgressbar()
Returns: void Description: Refreshes the position of the progress bar programmatically when the dimensions of the parent container change.
import { Component, ViewChild } from "@angular/core";
import { StepperComponent, StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<div>
<button (click)="refreshBar()">Refresh Progress Bar</button>
<button (click)="toggleWidth()">Toggle Container Width</button>
<div [style.width]="containerWidth">
<ejs-stepper #stepper>
<e-steps>
<e-step label="Step 1"></e-step>
<e-step label="Step 2"></e-step>
<e-step label="Step 3"></e-step>
</e-steps>
</ejs-stepper>
</div>
</div>
`,
styles: [`
div {
transition: width 0.3s ease;
}
`]
})
export class AppComponent {
@ViewChild('stepper') stepper!: StepperComponent;
containerWidth = '100%';
refreshBar(): void {
this.stepper.refreshProgressbar();
}
toggleWidth(): void {
this.containerWidth = this.containerWidth === '100%' ? '50%' : '100%';
setTimeout(() => this.refreshBar(), 300);
}
}reset()
Returns: void Description: Resets the Stepper state to initial values and moves to the first step.
import { Component, ViewChild } from "@angular/core";
import { StepperComponent, StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<div>
<button (click)="resetStepper()">Reset Stepper</button>
<p>Current Step: {{ currentStep }}</p>
<ejs-stepper #stepper (stepChanged)="onStepChanged($event)">
<e-steps>
<e-step label="Step 1"></e-step>
<e-step label="Step 2"></e-step>
<e-step label="Step 3"></e-step>
<e-step label="Step 4"></e-step>
</e-steps>
</ejs-stepper>
</div>
`
})
export class AppComponent {
@ViewChild('stepper') stepper!: StepperComponent;
currentStep = 0;
resetStepper(): void {
this.stepper.reset();
}
onStepChanged(args: any): void {
this.currentStep = args.activeStep;
}
}---
Events and Event Arguments
created
Description: Event triggered after the Stepper component is fully initialized and rendered.
@Component({
template: `
<ejs-stepper (created)="onCreated()">
<e-steps>
<e-step label="Step 1"></e-step>
<e-step label="Step 2"></e-step>
</e-steps>
</ejs-stepper>
`
})
export class AppComponent {
onCreated(): void {
console.log('Stepper has been created and initialized');
}
}stepChanged
Description: Event triggered after the active step has changed. Provides information about the new and previous step indices.
Event Arguments:
activeStep(number): Index of the currently active steppreviousStep(number): Index of the previously active stepisInteracted(boolean): Whether the change was triggered by user interactionevent(Event): The original browser eventelement(HTMLElement): The Stepper DOM elementname(string): Event name
import { Component } from "@angular/core";
import { StepperChangedEventArgs, StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<div>
<p>Current Step: {{ activeStep + 1 }} | Previous Step: {{ previousStep + 1 }}</p>
<p>User Interaction: {{ isInteracted }}</p>
<ejs-stepper (stepChanged)="onStepChanged($event)">
<e-steps>
<e-step label="Step 1"></e-step>
<e-step label="Step 2"></e-step>
<e-step label="Step 3"></e-step>
</e-steps>
</ejs-stepper>
</div>
`
})
export class AppComponent {
activeStep = 0;
previousStep = 0;
isInteracted = false;
onStepChanged(args: StepperChangedEventArgs): void {
console.log('Step changed:', args);
this.activeStep = args.activeStep;
this.previousStep = args.previousStep;
this.isInteracted = args.isInteracted;
}
}See also: events-and-interactions.md
stepChanging
Description: Event triggered before the active step changes. Can be used to validate or prevent step transition.
Event Arguments:
activeStep(number): Index of the step being navigated topreviousStep(number): Index of the current stepisInteracted(boolean): Whether triggered by user interactioncancel(boolean): Set totrueto prevent the step changeevent(Event): The original browser eventelement(HTMLElement): The Stepper DOM elementname(string): Event name
import { Component } from "@angular/core";
import { StepperChangingEventArgs, StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<div>
<p>Validation Message: {{ validationMessage }}</p>
<ejs-stepper (stepChanging)="onStepChanging($event)">
<e-steps>
<e-step label="Information"></e-step>
<e-step label="Confirmation"></e-step>
</e-steps>
</ejs-stepper>
</div>
`
})
export class AppComponent {
validationMessage = '';
onStepChanging(args: StepperChangingEventArgs): void {
console.log('Step changing:', args);
if (args.previousStep === 0 && args.activeStep === 1) {
// Validate before allowing step change
if (!this.isInformationComplete()) {
args.cancel = true;
this.validationMessage = 'Please complete all required fields';
}
}
}
isInformationComplete(): boolean {
// Your validation logic
return true;
}
}See also: events-and-interactions.md
stepClick
Description: Event triggered when a user clicks on a step.
Event Arguments:
activeStep(number): Index of the clicked steppreviousStep(number): Index of the previously active stepevent(Event): The original browser eventelement(HTMLElement): The Stepper DOM elementname(string): Event name
import { Component } from "@angular/core";
import { StepperClickEventArgs, StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<div>
<p>Clicked Step: {{ clickedStep }}</p>
<ejs-stepper (stepClick)="onStepClick($event)">
<e-steps>
<e-step label="Step 1"></e-step>
<e-step label="Step 2"></e-step>
<e-step label="Step 3"></e-step>
</e-steps>
</ejs-stepper>
</div>
`
})
export class AppComponent {
clickedStep = 0;
onStepClick(args: StepperClickEventArgs): void {
console.log('Step clicked:', args);
this.clickedStep = args.activeStep;
}
}See also: events-and-interactions.md
beforeStepRender
Description: Event triggered before each step is rendered. Can be used to customize step appearance dynamically.
Event Arguments:
index(number): Index of the step being renderedelement(HTMLElement): The Stepper DOM elementname(string): Event name
import { Component } from "@angular/core";
import { StepperRenderingEventArgs, StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<ejs-stepper (beforeStepRender)="onBeforeStepRender($event)">
<e-steps>
<e-step label="Step 1"></e-step>
<e-step label="Step 2"></e-step>
<e-step label="Step 3"></e-step>
</e-steps>
</ejs-stepper>
`
})
export class AppComponent {
onBeforeStepRender(args: StepperRenderingEventArgs): void {
console.log('Rendering step:', args.index);
// Customize step appearance before rendering
if (args.index === 1) {
// Apply custom styling to step 2
console.log('Step 2 is about to be rendered');
}
}
}See also: events-and-interactions.md
---
Enumerations
StepType
Defines the display style of steps in the Stepper.
export enum StepType {
Default = 'Default', // Icons with labels
Label = 'Label', // Labels only
Indicator = 'Indicator' // Icons or numbers only
}StepStatus
Defines the progress status of a step.
export enum StepStatus {
NotStarted = 'NotStarted',
InProgress = 'InProgress',
Completed = 'Completed'
}StepLabelPosition
Defines the position of step labels relative to indicators.
export enum StepLabelPosition {
Top = 'Top', // Label above indicator
Bottom = 'Bottom', // Label below indicator
Start = 'Start', // Label on the left side
End = 'End' // Label on the right side
}StepperOrientation
Defines the layout orientation of the Stepper.
export enum StepperOrientation {
Horizontal = 'Horizontal', // Steps arranged horizontally
Vertical = 'Vertical' // Steps arranged vertically
}---
Related Documentation
- Getting Started
- Steps Configuration
- Step Types
- Orientations and Layouts
- Events and Interactions
- Validation and Flow Control
- Templates and Customization
- Advanced Features
Handling Events and Interactions in Angular Stepper
Table of Contents
- Event Overview
- Created Event
- StepChanged Event
- StepChanging Event
- BeforeStepRender Event
- StepClick Event
- Event Arguments Reference
- Event Patterns
Event Overview
The Stepper component fires events at key moments during user interaction and component lifecycle. These events allow you to respond to user actions, validate data, and customize behavior.
Available Events
| Event | Trigger | Use Case |
|---|---|---|
created | Component rendering complete | Initialize dependent components |
stepChanged | After step changes | Track navigation history |
stepChanging | Before step changes | Validate data, prevent navigation |
beforeStepRender | Before step renders | Customize step content |
stepClick | User clicks step indicator | Handle direct step access |
Created Event
The created event fires when the Stepper component finishes rendering. Use this event to initialize dependent components or perform setup tasks.
Created Event Example
import { Component } from "@angular/core";
import { StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<div class="stepper-container">
<h2>Welcome to Setup Wizard</h2>
<ejs-stepper (created)="onCreated()">
<e-steps>
<e-step label="Step 1"></e-step>
<e-step label="Step 2"></e-step>
<e-step label="Step 3"></e-step>
</e-steps>
</ejs-stepper>
<div class="message" *ngIf="message">{{ message }}</div>
</div>
`,
styles: [`
.stepper-container {
padding: 20px;
max-width: 600px;
margin: 0 auto;
}
.message {
margin-top: 20px;
padding: 10px;
background-color: #e0f2f1;
border-left: 4px solid #00897b;
}
`]
})
export class AppComponent {
message = '';
onCreated(): void {
console.log('Stepper component created');
this.message = 'Stepper initialized successfully';
// Initialize dependent components
this.initializeDependencies();
}
initializeDependencies(): void {
// Load data, initialize services, etc.
}
}When to Use Created
- Initialize related components
- Load initial data or configuration
- Set up event listeners
- Start timers or processes
- Perform one-time setup tasks
StepChanged Event
The stepChanged event fires after the active step has changed. Use this event to respond to step changes, track user flow, or perform actions on the new step.
StepChanged Event Example
import { Component } from "@angular/core";
import { StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
import { StepperChangedEventArgs } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<div class="stepper-container">
<ejs-stepper (stepChanged)="onStepChanged($event)">
<e-steps>
<e-step label="Personal Info"></e-step>
<e-step label="Address"></e-step>
<e-step label="Payment"></e-step>
<e-step label="Confirmation"></e-step>
</e-steps>
</ejs-stepper>
<div class="history">
<h3>Navigation History</h3>
<ul>
<li *ngFor="let entry of history">{{ entry }}</li>
</ul>
</div>
</div>
`,
styles: [`
.stepper-container {
padding: 20px;
max-width: 600px;
margin: 0 auto;
}
.history {
margin-top: 20px;
padding: 10px;
background-color: #f5f5f5;
border: 1px solid #ddd;
border-radius: 4px;
}
`]
})
export class AppComponent {
history: string[] = [];
onStepChanged(args: StepperChangedEventArgs): void {
const timestamp = new Date().toLocaleTimeString();
const message = `Moved to Step ${args.activeStep + 1} at ${timestamp}`;
this.history.push(message);
console.log(message);
// Update page title or breadcrumb
this.updatePageState(args.activeStep);
}
updatePageState(stepIndex: number): void {
const stepNames = ['Personal Info', 'Address', 'Payment', 'Confirmation'];
console.log(`Current Step: ${stepNames[stepIndex]}`);
}
}StepChanged Event Args
activeStep(number): Index of the currently active step (0-indexed)previousStep(number): Index of the previously active step (0-indexed)isInteracted(boolean): Whether the change was triggered by user interactionevent(Event): The original browser eventelement(HTMLElement): The Stepper DOM elementname(string): Event name
When to Use StepChanged
- Track user navigation flow
- Update related UI elements
- Load step-specific content
- Record analytics/user behavior
- Update breadcrumbs or page titles
StepChanging Event
The stepChanging event fires before the step changes. Use this event to validate data, prevent invalid navigation, and ask for confirmation.
StepChanging Event Example - Form Validation
import { Component } from "@angular/core";
import { StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
import { StepperChangingEventArgs } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<div class="form-stepper">
<ejs-stepper (stepChanging)="onStepChanging($event)">
<e-steps>
<e-step label="Personal Details">
<div class="step-content">
<input [(ngModel)]="personalInfo.name" placeholder="Full Name">
<input [(ngModel)]="personalInfo.email" placeholder="Email">
</div>
</e-step>
<e-step label="Address">
<div class="step-content">
<input [(ngModel)]="address.street" placeholder="Street">
<input [(ngModel)]="address.city" placeholder="City">
</div>
</e-step>
<e-step label="Confirmation">
<div class="step-content">Review and confirm</div>
</e-step>
</e-steps>
</ejs-stepper>
<div class="error" *ngIf="errorMessage">{{ errorMessage }}</div>
</div>
`,
styles: [`
.form-stepper {
padding: 20px;
max-width: 600px;
margin: 0 auto;
}
.step-content {
padding: 20px;
border: 1px solid #ddd;
border-radius: 4px;
}
input {
display: block;
width: 100%;
margin: 10px 0;
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
}
.error {
margin-top: 10px;
padding: 10px;
background-color: #ffebee;
color: #c62828;
border-radius: 4px;
}
`]
})
export class AppComponent {
personalInfo = { name: '', email: '' };
address = { street: '', city: '' };
errorMessage = '';
onStepChanging(args: StepperChangingEventArgs): void {
this.errorMessage = '';
// Validate current step before allowing change
if (args.activeStep === 0 && args.previousStep === 1) {
// Returning to first step, validation passes
return;
}
if (args.previousStep === 0) {
if (!this.validatePersonalInfo()) {
this.errorMessage = 'Please fill in all personal information fields';
args.cancel = true; // Prevent step change
return;
}
}
if (args.previousStep === 1) {
if (!this.validateAddress()) {
this.errorMessage = 'Please fill in all address fields';
args.cancel = true; // Prevent step change
return;
}
}
}
validatePersonalInfo(): boolean {
return this.personalInfo.name.trim() !== '' &&
this.personalInfo.email.trim() !== '';
}
validateAddress(): boolean {
return this.address.street.trim() !== '' &&
this.address.city.trim() !== '';
}
}StepChanging Event Args
activeStep: Target step indexpreviousStep: Current step indexcancel: Set totrueto prevent step change
When to Use StepChanging
- Validate form data before moving forward
- Ask for confirmation before leaving a step
- Save data to server before progression
- Prevent navigation to invalid states
- Perform async validation
BeforeStepRender Event
The beforeStepRender event fires before a step renders. Use this to customize step appearance, content, or add dynamic elements.
BeforeStepRender Event Example
import { Component } from "@angular/core";
import { StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
import { StepperRenderingEventArgs } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<ejs-stepper (beforeStepRender)="onBeforeStepRender($event)">
<e-steps>
<e-step label="Step 1"></e-step>
<e-step label="Step 2"></e-step>
<e-step label="Step 3"></e-step>
<e-step label="Step 4"></e-step>
</e-steps>
</ejs-stepper>
`
})
export class AppComponent {
onBeforeStepRender(args: StepperRenderingEventArgs): void {
// Customize step based on conditions
if (args.step.index === 2) {
// Add special styling or marking to step 3
args.step.cssClass = 'important-step';
}
}
}StepperRenderingEventArgs
index: Index of the step being rendered (0-indexed)element: The Stepper DOM elementname: Event name string
When to Use BeforeStepRender
- Add dynamic CSS classes
- Conditionally disable/enable steps
- Customize step appearance
- Add loading indicators
- Dynamically determine step availability
StepClick Event
The stepClick event fires when the user clicks on a step indicator or label. Use this to handle direct step navigation or custom click behavior.
StepClick Event Example
import { Component } from "@angular/core";
import { StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
import { StepperClickEventArgs } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<div class="click-example">
<ejs-stepper (stepClick)="onStepClick($event)">
<e-steps>
<e-step label="Cart"></e-step>
<e-step label="Delivery"></e-step>
<e-step label="Payment"></e-step>
<e-step label="Complete"></e-step>
</e-steps>
</ejs-stepper>
<div class="feedback" *ngIf="feedback">{{ feedback }}</div>
</div>
`,
styles: [`
.click-example {
padding: 20px;
}
.feedback {
margin-top: 20px;
padding: 10px;
background-color: #e3f2fd;
border-left: 4px solid #1976d2;
}
`]
})
export class AppComponent {
feedback = '';
onStepClick(args: StepperClickEventArgs): void {
this.feedback = `You clicked on Step ${args.activeStep + 1}`;
console.log(`Step ${args.activeStep} clicked`, args);
}
}StepClickEventArgs
activeStep: Index of the clicked step (0-indexed)previousStep: Index of the previously active step (0-indexed)event: The original browser eventelement: The Stepper DOM elementname: Event name string
When to Use StepClick
- Track which steps users click on
- Provide feedback on step clicks
- Allow direct navigation (if not linear)
- Prevent click on future steps
- Analytics tracking
Event Arguments Reference
Common Event Arguments
All event arguments extend the base event object with the following common properties:
| Property | Type | Description |
|---|---|---|
event | Event | The original browser DOM event |
element | HTMLElement | The Stepper component's root DOM element |
name | string | Name of the event being fired |
StepperChangedEventArgs
Fired after step change is complete.
| Property | Type | Description |
|---|---|---|
activeStep | number | Index of the currently active step (0-indexed) |
previousStep | number | Index of the previously active step (0-indexed) |
isInteracted | boolean | true if triggered by user interaction, false if programmatic |
event | Event | The original browser event |
element | HTMLElement | The Stepper DOM element |
name | string | Event name ('stepChanged') |
StepperChangingEventArgs
Fired before step change, can be prevented.
| Property | Type | Description |
|---|---|---|
activeStep | number | Index of the target step (0-indexed) |
previousStep | number | Index of the current step (0-indexed) |
cancel | boolean | Set to true to prevent the step change. Default: false |
isInteracted | boolean | true if triggered by user interaction, false if programmatic |
event | Event | The original browser event |
element | HTMLElement | The Stepper DOM element |
name | string | Event name ('stepChanging') |
StepperClickEventArgs
Fired when user clicks on a step.
| Property | Type | Description |
|---|---|---|
activeStep | number | Index of the clicked step (0-indexed) |
previousStep | number | Index of the previously active step (0-indexed) |
event | Event | The original browser event |
element | HTMLElement | The Stepper DOM element |
name | string | Event name ('stepClick') |
StepperRenderingEventArgs
Fired before a step renders.
| Property | Type | Description |
|---|---|---|
index | number | Index of the step about to render (0-indexed) |
element | HTMLElement | The Stepper DOM element |
name | string | Event name ('beforeStepRender') |
Event Patterns
Pattern 1: Complete Form Workflow
onCreated(): void {
// Load form data
}
onStepChanging(args: StepperChangingEventArgs): void {
// Validate current step data
if (!isValid()) {
args.cancel = true;
}
}
onStepChanged(args: StepperChangedEventArgs): void {
// Save previous step data
// Load new step data
}Pattern 2: Linear Workflow
onStepClick(args: StepperClickEventArgs): void {
// Allow only moving forward
if (args.activeStep <= this.currentStep) {
// Allowed
} else {
args.cancel = true; // Prevent moving to future step
}
}Pattern 3: Async Validation
async onStepChanging(args: StepperChangingEventArgs) {
const isValid = await this.validateWithServer();
if (!isValid) {
args.cancel = true;
}
}Best Practices
1. Prevent data loss: Use stepChanging to validate before leaving 2. Provide feedback: Use stepChanged to update UI 3. Initialize once: Use created for one-time setup 4. Track user journey: Log navigation in stepChanged 5. Clear error messages: Reset errors when user takes action
See also: validation-and-flow.md for form validation patterns.
Getting Started with Angular Stepper
Table of Contents
- Dependencies
- Setup Angular Environment
- Create a New Application
- Install Syncfusion Package
- Add Stepper Component
- Using CSS Themes
- Running the Application
Dependencies
The following dependencies are required to use the Stepper component:
@syncfusion/ej2-angular-navigations
├── @syncfusion/ej2-base
├── @syncfusion/ej2-popups
├── @syncfusion/ej2-navigations
└── @syncfusion/ej2-angular-baseThese packages are automatically installed when you install the main Syncfusion navigations package.
Setup Angular Environment
Install Angular CLI
Use Angular CLI to set up your Angular application:
npm install -g @angular/cliInstall Specific Angular CLI Version
To install a particular version of Angular CLI required for your project:
npm install -g @angular/cli@21.0.0Create a New Application
Generate a new Angular application using the Angular CLI:
ng new syncfusion-angular-appDuring the setup wizard, you'll be prompted to configure:
? Which stylesheet format would you like to use? (Use arrow keys)
> CSS [ https://developer.mozilla.org/docs/Web/CSS ]
Sass (SCSS) [ https://sass-lang.com/documentation/syntax#scss ]
Sass (Indented) [ https://sass-lang.com/documentation/syntax#the-indented-syntax ]
Less [ http://lesscss.org/ ]For SCSS support, use:
ng new syncfusion-angular-app --style=scssServer-side rendering (SSR) prompt: Choose the appropriate configuration for your needs.
Additional prompts:
- Select AI tool support if needed, or choose 'none'
- Configure any other project-specific settings
Navigate to your project directory:
cd syncfusion-angular-appInstall Syncfusion Package
Install the Syncfusion navigations package:
npm install @syncfusion/ej2-angular-navigationsThis command installs the Stepper component along with all required dependencies.
Add Stepper Component
Basic Stepper Implementation
Create a basic stepper with steps in your component:
import { Component } from "@angular/core";
import { StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
// Component logic here
}Bootstrap your application:
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));HTML Template
Add the Stepper component to your template with steps:
<div class="stepper-container">
<ejs-stepper>
<e-steps>
<e-step label="Step 1" iconCss="sf-icon-home"></e-step>
<e-step label="Step 2" iconCss="sf-icon-settings"></e-step>
<e-step label="Step 3" iconCss="sf-icon-check"></e-step>
<e-step label="Step 4" iconCss="sf-icon-success"></e-step>
</e-steps>
</ejs-stepper>
</div>Component Styling
Basic styling for the stepper container:
.stepper-container {
padding: 20px;
max-width: 800px;
margin: 0 auto;
}Using CSS Themes
Syncfusion Stepper supports multiple built-in themes. Import the theme CSS in your global styles file.
Import Theme in Main CSS
Add to your styles.css:
/* Material Theme (Default) */
@import '@syncfusion/ej2-angular-navigations/styles/material.css';
/* Alternative Themes */
/* @import '@syncfusion/ej2-angular-navigations/styles/bootstrap.css'; */
/* @import '@syncfusion/ej2-angular-navigations/styles/fluent.css'; */
/* @import '@syncfusion/ej2-angular-navigations/styles/tailwind.css'; */Theme Options
Available themes:
- material - Material Design (default)
- bootstrap - Bootstrap 5 style
- bootstrap4 - Bootstrap 4 style
- fluent - Microsoft Fluent Design
- tailwind - Tailwind CSS theme
- highcontrast - High contrast for accessibility
Choose one based on your application's design system.
Running the Application
Start the development server:
ng serveOpen your browser and navigate to:
http://localhost:4200You should see your Stepper component rendering with the configured steps.
Complete Getting Started Example
Combine all elements for a complete working example:
// app.component.ts
import { Component } from "@angular/core";
import { StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<div class="stepper-container">
<h1>Order Workflow</h1>
<ejs-stepper>
<e-steps>
<e-step label="Cart" iconCss="sf-icon-cart"></e-step>
<e-step label="Delivery Address" iconCss="sf-icon-transport"></e-step>
<e-step label="Payment" iconCss="sf-icon-payment"></e-step>
<e-step label="Confirmation" iconCss="sf-icon-success"></e-step>
</e-steps>
</ejs-stepper>
</div>
`,
styles: [`
.stepper-container {
padding: 20px;
max-width: 800px;
margin: 0 auto;
}
h1 {
text-align: center;
margin-bottom: 30px;
}
`]
})
export class AppComponent { }Troubleshooting
Issue: Styles not applied?
- Ensure CSS theme is imported in
styles.css - Check that
@syncfusion/ej2-angular-navigationspackage is installed
Issue: Component not rendering?
- Verify
StepperModuleis imported in component - Check standalone component setup with
imports: [StepperModule]
Issue: Icons not displaying?
- Ensure icon library CSS is imported (check
iconCssvalues) - Icon classes must be defined in your CSS or use a font icon library
Next Steps: Once you have the basic stepper working, explore configuring steps with steps-configuration.md and different step types with step-types.md.
Setting Orientations and Layouts in Angular Stepper
Table of Contents
Horizontal Orientation
The Horizontal orientation is the default display style, where steps are arranged left-to-right in a row. This orientation is ideal for workflows displayed above content or in the main content area.
Default Horizontal Layout
import { Component } from "@angular/core";
import { StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<div class="horizontal-layout">
<h2>Horizontal Stepper (Default)</h2>
<ejs-stepper orientation="Horizontal">
<e-steps>
<e-step label="Step 1" iconCss="sf-icon-home"></e-step>
<e-step label="Step 2" iconCss="sf-icon-settings"></e-step>
<e-step label="Step 3" iconCss="sf-icon-database"></e-step>
<e-step label="Step 4" iconCss="sf-icon-check"></e-step>
</e-steps>
</ejs-stepper>
<div class="content">
<!-- Step content here -->
</div>
</div>
`,
styles: [`
.horizontal-layout {
padding: 20px;
max-width: 900px;
margin: 0 auto;
}
.content {
padding: 20px 0;
border: 1px solid #ddd;
border-top: none;
}
`]
})
export class AppComponent { }Implicit Horizontal (Omitting Orientation)
The stepper defaults to horizontal orientation if not specified:
<ejs-stepper>
<e-steps>
<e-step label="Step 1"></e-step>
<e-step label="Step 2"></e-step>
<e-step label="Step 3"></e-step>
</e-steps>
</ejs-stepper>When to Use Horizontal
- Standard workflows: Multi-step forms, checkout processes
- Wide layouts: Desktop applications with ample width
- Content below: When step details appear below the stepper
- Tab-like navigation: Multi-page forms within a single view
- User expectations: Horizontal is the standard expectation for steppers
Features of Horizontal Orientation
- Default behavior: No configuration needed
- Space efficient: Uses width effectively
- Visual flow: Clear left-to-right progression
- Content friendly: Leaves vertical space for step content
- Responsive: Adapts to available width
Vertical Orientation
The Vertical orientation displays steps in a column, where steps are arranged top-to-bottom. This is useful for tall layouts, sidebars, or when horizontal space is limited.
Vertical Layout Example
import { Component } from "@angular/core";
import { StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<div class="vertical-layout">
<div class="container">
<div class="sidebar">
<h3>Setup Guide</h3>
<ejs-stepper orientation="Vertical">
<e-steps>
<e-step label="Install" iconCss="sf-icon-download"></e-step>
<e-step label="Configure" iconCss="sf-icon-settings"></e-step>
<e-step label="Deploy" iconCss="sf-icon-upload"></e-step>
<e-step label="Monitor" iconCss="sf-icon-chart"></e-step>
</e-steps>
</ejs-stepper>
</div>
<div class="main-content">
<!-- Main content area -->
</div>
</div>
</div>
`,
styles: [`
.vertical-layout {
padding: 20px;
}
.container {
display: flex;
gap: 20px;
max-width: 1200px;
margin: 0 auto;
}
.sidebar {
flex: 0 0 300px;
border-right: 1px solid #ddd;
padding-right: 20px;
}
.main-content {
flex: 1;
padding: 20px;
}
h3 {
margin-top: 0;
}
`]
})
export class AppComponent { }Vertical in Drawer/Modal
Use vertical orientation in sidebars, drawers, or modals:
<div class="drawer">
<div class="drawer-header">
<h3>Wizard Steps</h3>
</div>
<ejs-stepper orientation="Vertical">
<e-steps>
<e-step label="Personal Details"></e-step>
<e-step label="Address"></e-step>
<e-step label="Verification"></e-step>
<e-step label="Confirmation"></e-step>
</e-steps>
</ejs-stepper>
</div>When to Use Vertical
- Sidebar navigation: Multi-step processes in sidebars
- Narrow layouts: Mobile devices or responsive designs
- Drawer/modal: Wizards in modals or drawer components
- Vertical space available: When you have tall viewing areas
- Multi-section workflows: Complex processes with many steps
Features of Vertical Orientation
- Space vertical: Uses height instead of width
- Sidebar friendly: Works well in sidebars
- Mobile responsive: Adapts to narrow screens
- Scrollable: Can scroll vertically if many steps
- Proximity: Step details can be beside steps
Choosing Orientation
Decision Matrix
| Scenario | Horizontal | Vertical |
|---|---|---|
| Wide desktop layout | ✅ | ⚠️ |
| Mobile/narrow screen | ⚠️ | ✅ |
| Sidebar navigation | ✗ | ✅ |
| Horizontal space abundant | ✅ | ⚠️ |
| Vertical space abundant | ⚠️ | ✅ |
| Many steps (5+) | ⚠️ | ✅ |
| Few steps (1-3) | ✅ | ✓ |
Recommendation by Layout
Use Horizontal:
- Standard full-width layouts
- E-commerce checkout
- Multi-step forms in modals
- Documentation workflows
- Sufficient width available
Use Vertical:
- Sidebar-based UI
- Mobile/responsive layouts
- Drawer/modal wizards
- Multi-section forms
- Space-constrained width
Responsive Design
Implement responsive orientation switching for different screen sizes:
import { Component, ViewChild } from "@angular/core";
import { StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
import { ChangeDetectorRef } from "@angular/core";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<ejs-stepper [orientation]="screenOrientation">
<e-steps>
<e-step label="Step 1" iconCss="sf-icon-cart"></e-step>
<e-step label="Step 2" iconCss="sf-icon-transport"></e-step>
<e-step label="Step 3" iconCss="sf-icon-payment"></e-step>
<e-step label="Step 4" iconCss="sf-icon-success"></e-step>
</e-steps>
</ejs-stepper>
`
})
export class AppComponent {
screenOrientation = this.getOrientation();
constructor(private cdr: ChangeDetectorRef) {
window.addEventListener('resize', () => {
this.screenOrientation = this.getOrientation();
this.cdr.detectChanges();
});
}
getOrientation(): 'Horizontal' | 'Vertical' {
return window.innerWidth < 768 ? 'Vertical' : 'Horizontal';
}
}Breakpoint Guidelines
/* Extra small devices (phones) */
@media (max-width: 576px) {
/* Use Vertical orientation */
}
/* Small devices (tablets) */
@media (max-width: 768px) {
/* Use Vertical orientation */
}
/* Medium devices and larger */
@media (min-width: 769px) {
/* Use Horizontal orientation */
}Combining with Step Types
Orientations work with all step types:
<!-- Horizontal + Indicator Only (compact desktop) -->
<ejs-stepper orientation="Horizontal" stepType="Indicator">
<e-steps>
<e-step iconCss="sf-icon-1"></e-step>
<e-step iconCss="sf-icon-2"></e-step>
<e-step iconCss="sf-icon-3"></e-step>
</e-steps>
</ejs-stepper>
<!-- Vertical + Default (sidebar with labels) -->
<ejs-stepper orientation="Vertical" stepType="Default">
<e-steps>
<e-step label="Step 1" iconCss="sf-icon-1"></e-step>
<e-step label="Step 2" iconCss="sf-icon-2"></e-step>
<e-step label="Step 3" iconCss="sf-icon-3"></e-step>
</e-steps>
</ejs-stepper>Best Practices
1. Default is horizontal: Most users expect horizontal steppers 2. Mobile-first: Plan vertical layout early for responsive designs 3. Test both: Verify usability in both orientations 4. Clear connections: Use visual lines to connect steps 5. Responsive switching: Automatically adjust orientation on resize 6. Content placement: Position step content appropriately for orientation
See also: step-types.md for display style options, getting-started.md for basic setup.
Step Types in Angular Stepper
Table of Contents
Default Type
The Default type displays steps with a combination of indicators (icons or numbers) and labels. This is the standard and recommended display style for most use cases.
Default Type Example
import { Component } from "@angular/core";
import { StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<div class="iconWithLabel">
<ejs-stepper stepType="Default">
<e-steps>
<e-step label="Cart" iconCss="sf-icon-cart"></e-step>
<e-step label="Delivery Address" iconCss="sf-icon-transport"></e-step>
<e-step label="Payment" iconCss="sf-icon-payment"></e-step>
<e-step label="Confirmation" iconCss="sf-icon-success"></e-step>
</e-steps>
</ejs-stepper>
</div>
`,
styles: [`
.iconWithLabel {
padding: 20px;
max-width: 800px;
margin: 0 auto;
}
`]
})
export class AppComponent { }When to Use Default Type
- When you need both visual icons and text labels
- For complex workflows where clarity is important
- General-purpose applications that prioritize accessibility
- Mobile and desktop responsive designs
- Multi-step forms and wizards
Features of Default Type
- Visual Icons: Shows icons or numbered indicators
- Text Labels: Displays descriptive text for each step
- Clear Navigation: Easy to understand step information
- Accessibility: Icon + label provides redundant information for accessibility
- Space Utilization: Takes moderate space for optimal visibility
Label Positions
You can display the label on the top, bottom, start, or end side of the steps using the labelPosition property. This allows flexible label positioning based on your layout requirements.
Supported Label Positions
| Value | Description |
|---|---|
Top | Positions the label at the top of each step. |
Bottom | Positions the label at the bottom of each step. |
Start | Positions the label to the left side of each step. |
End | Positions the label to the right side of each step. |
Label Position Example
import { Component, ViewChild } from "@angular/core";
import { StepperComponent, StepperAllModule, StepperModule } from '@syncfusion/ej2-angular-navigations';
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<div class="stepperWithLabel">
<div class="e-btn-group labelPosition">
<input type="radio" id="start" name="position" value="start" (click)="updateLabelPosition($event);" />
<label class="e-btn" for="start">Start</label>
<input type="radio" id="end" name="position" value="end" (click)="updateLabelPosition($event);" />
<label class="e-btn" for="end">End</label>
<input type="radio" id="top" name="position" value="top" (click)="updateLabelPosition($event);" />
<label class="e-btn" for="top">Top</label>
<input type="radio" id="bottom" name="position" value="bottom" (click)="updateLabelPosition($event);" checked />
<label class="e-btn" for="bottom">Bottom</label>
</div>
<div class="stepper-section">
<ejs-stepper #ejStepper>
<e-steps>
<e-step label="Cart" iconCss="sf-icon-cart"></e-step>
<e-step label="Shipped" iconCss="sf-icon-transport"></e-step>
<e-step label="Payment" iconCss="sf-icon-payment"></e-step>
<e-step label="Delivered" iconCss="sf-icon-success"></e-step>
</e-steps>
</ejs-stepper>
</div>
</div>
`,
styles: [`
.stepperWithLabel {
padding: 20px;
}
.labelPosition {
margin-bottom: 20px;
}
`]
})
export class AppComponent {
@ViewChild('ejStepper') stepper: StepperComponent | any;
public updateLabelPosition(args: any): void {
// Capitalize the position value: 'start' -> 'Start', 'end' -> 'End', etc.
const position = args.currentTarget.value;
const capitalizedPosition = position.charAt(0).toUpperCase() + position.slice(1);
this.stepper.labelPosition = capitalizedPosition;
};
}When to Use Each Position
- Top: Default position for horizontal steppers, works well with icons
- Bottom: Common for horizontal layouts, provides clear separation
- Start (Left): Works well for vertical steppers or RTL layouts
- End (Right): Alternative layout for horizontal steppers with labels on the right
Label Position Guidelines
1. Horizontal Steppers: Use Top or Bottom positions 2. Vertical Steppers: Use Start or End positions 3. Accessibility: Top or Bottom positions are typically more accessible 4. Responsive Design: Consider changing position on mobile devices 5. Icon Visibility: Ensure labels don't overlap with icons
Indicator Only Type
The Indicator Only type displays only the step indicators (icons or numbers) without text labels. This creates a compact, icon-based navigation.
Indicator Only Type Example
import { Component } from "@angular/core";
import { StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<div class="indicatorOnly">
<ejs-stepper stepType="Indicator">
<e-steps>
<e-step iconCss="sf-icon-cart"></e-step>
<e-step iconCss="sf-icon-transport"></e-step>
<e-step iconCss="sf-icon-payment"></e-step>
<e-step iconCss="sf-icon-success"></e-step>
</e-steps>
</ejs-stepper>
</div>
`,
styles: [`
.indicatorOnly {
padding: 20px;
max-width: 400px;
margin: 0 auto;
}
`]
})
export class AppComponent { }When to Use Indicator Only Type
- When space is limited (mobile devices, sidebars)
- For experienced users familiar with the workflow
- When labels would create clutter
- Compact dashboard or widget layouts
- Icon-based interfaces with context labels elsewhere
- Progressive disclosure patterns
Features of Indicator Only Type
- Minimal Space: Compact footprint on screen
- Clean Design: Reduces visual clutter
- Icon-Focused: Relies on clear, intuitive icons
- Mobile-Friendly: Works well on small screens
- Supplementary Labels: Can add tooltips for additional context
Best Practices for Indicator Only
- Use clear, universally recognized icons
- Ensure icons are visually distinct
- Consider adding tooltips when users hover
- Provide step descriptions elsewhere in the UI
- Test with users unfamiliar with your workflow
Label Only Type
The Label Only type displays only text labels without icons or indicators. This style is useful for text-based navigation with minimal visual decoration.
Label Only Type Example
import { Component } from "@angular/core";
import { StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<div class="labelOnly">
<ejs-stepper stepType="Label">
<e-steps>
<e-step label="Cart"></e-step>
<e-step label="Delivery Address"></e-step>
<e-step label="Payment"></e-step>
<e-step label="Confirmation"></e-step>
</e-steps>
</ejs-stepper>
</div>
`,
styles: [`
.labelOnly {
padding: 20px;
max-width: 600px;
margin: 0 auto;
}
`]
})
export class AppComponent { }When to Use Label Only Type
- When icons might be ambiguous or unclear
- Text-heavy applications or internal tools
- Accessibility-focused designs
- Multi-language applications where labels adapt
- Formal or professional interfaces
- When step descriptions are self-explanatory
Features of Label Only Type
- Text-Based: Clear, readable description for each step
- Icon-Free: No visual icons needed
- Flexibility: Labels can be long and descriptive
- Simplicity: Straightforward text navigation
- Localization: Easy to translate and adapt
Type Selection Guide
Decision Matrix
| Scenario | Default | Indicator | Label |
|---|---|---|---|
| Wide layout | ✅ | ✅ | ✅ |
| Mobile/narrow | ⚠️ | ✅ | ⚠️ |
| Icon clear | ✅ | ✅ | ✗ |
| Icon unclear | ✅ | ✗ | ✅ |
| Space limited | ⚠️ | ✅ | ⚠️ |
| Accessibility | ✅ | ⚠️ | ✅ |
| Modern design | ✅ | ✅ | ⚠️ |
Recommendation by Use Case
Default Type (Recommended for most cases)
- Multi-step forms and wizards
- E-commerce checkout flows
- Onboarding sequences
- General workflows
Indicator Only Type
- Mobile-first designs
- Compact dashboards
- Icon-rich interfaces
- Space-constrained layouts
Label Only Type
- Accessibility-critical applications
- Text-heavy internal tools
- Multi-language applications
- Formal or enterprise interfaces
Switching Step Types
Change the step type using the stepType property. The component supports 'Default', 'Indicator', and 'Label' values:
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
template: `
<div class="controls">
<button (click)="setStepType('Default')">Default</button>
<button (click)="setStepType('Indicator')">Indicator</button>
<button (click)="setStepType('Label')">Label Only</button>
</div>
<ejs-stepper [stepType]="selectedType">
<e-steps>
<e-step label="Step 1" iconCss="sf-icon-cart"></e-step>
<e-step label="Step 2" iconCss="sf-icon-transport"></e-step>
<e-step label="Step 3" iconCss="sf-icon-payment"></e-step>
</e-steps>
</ejs-stepper>
`
})
export class AppComponent {
selectedType = 'Default';
setStepType(type: string) {
this.selectedType = type;
}
}Best Practices
1. Default for clarity: Use Default type unless space is severely constrained 2. Icon visibility: If using Indicator type, ensure icons are clear and testable 3. Mobile responsive: Use Indicator on mobile, Default on desktop using responsive design 4. Consistency: Keep the same type throughout your application 5. Testing: Validate that users understand your chosen type
See also: orientations-and-layouts.md for layout options, steps-configuration.md for configuring icons and labels.
Configuring Steps in Angular Stepper
Table of Contents
- Adding Steps
- Configuring Icons
- Step Labels and Text
- Step Properties
- Icon and Label Combinations
- Setting Active Step
- Optional Steps
- Disabling Steps
- Setting Readonly
- Step Status
- Step Validation
- Label Positioning
Adding Steps
The Angular Stepper allows you to add steps using the <e-step> tag directive. Each step can be configured with various properties to customize its appearance and behavior.
Basic Step Definition
Define steps using the <e-step> directive inside <e-steps>:
<ejs-stepper>
<e-steps>
<e-step></e-step>
<e-step></e-step>
<e-step></e-step>
</e-steps>
</ejs-stepper>Configuring Icons
Using Icon CSS Classes
Define a CSS class to display an icon for each step using the iconCss property:
import { Component } from "@angular/core";
import { StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<div class="stepperIcon">
<ejs-stepper>
<e-steps>
<e-step iconCss="sf-icon-cart"></e-step>
<e-step iconCss="sf-icon-transport"></e-step>
<e-step iconCss="sf-icon-payment"></e-step>
<e-step iconCss="sf-icon-success"></e-step>
</e-steps>
</ejs-stepper>
</div>
`,
styles: [`
.stepperIcon {
padding: 20px;
}
`]
})
export class AppComponent { }Icon Font Libraries
Use any icon font library by providing the appropriate CSS class. Common options:
- Material Icons:
material-iconswith icon class name - Font Awesome:
fa fa-*classes - Bootstrap Icons:
bi bi-*classes - Syncfusion Icons:
sf-icon-*classes
Example with Font Awesome:
<ejs-stepper>
<e-steps>
<e-step iconCss="fa fa-shopping-cart"></e-step>
<e-step iconCss="fa fa-truck"></e-step>
<e-step iconCss="fa fa-credit-card"></e-step>
<e-step iconCss="fa fa-check-circle"></e-step>
</e-steps>
</ejs-stepper>Step Labels and Text
Defining Labels
The label property displays text for each step:
<ejs-stepper>
<e-steps>
<e-step label="Personal Info"></e-step>
<e-step label="Address"></e-step>
<e-step label="Confirmation"></e-step>
</e-steps>
</ejs-stepper>Custom Text Content
Use the text property for additional text (note: typically use label for primary text):
<ejs-stepper>
<e-steps>
<e-step label="Step 1" text="Enter your information"></e-step>
<e-step label="Step 2" text="Confirm your address"></e-step>
<e-step label="Step 3" text="Complete payment"></e-step>
</e-steps>
</ejs-stepper>Step Properties
The StepModel interface defines properties for each step:
| Property | Type | Description |
|---|---|---|
iconCss | string | CSS class for step icon |
label | string | Display text for the step |
text | string | Additional text content for the step |
cssClass | string | Custom CSS class for styling |
status | StepStatus | Step status (NotStarted, InProgress, Completed, Error) |
optional | boolean | Mark step as optional |
disabled | boolean | Disable step interaction |
Icon and Label Combinations
Icons with Labels
Combine icons and labels for comprehensive step indicators:
import { Component } from "@angular/core";
import { StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<div class="iconWithLabel">
<ejs-stepper>
<e-steps>
<e-step label="Cart" iconCss="sf-icon-cart"></e-step>
<e-step label="Delivery Address" iconCss="sf-icon-transport"></e-step>
<e-step label="Payment" iconCss="sf-icon-payment"></e-step>
<e-step label="Confirmation" iconCss="sf-icon-success"></e-step>
</e-steps>
</ejs-stepper>
</div>
`,
styles: [`
.iconWithLabel {
max-width: 800px;
margin: 20px auto;
}
`]
})
export class AppComponent { }Icons Only
For compact layouts, use only icons without labels:
<ejs-stepper>
<e-steps>
<e-step iconCss="sf-icon-cart"></e-step>
<e-step iconCss="sf-icon-transport"></e-step>
<e-step iconCss="sf-icon-payment"></e-step>
<e-step iconCss="sf-icon-success"></e-step>
</e-steps>
</ejs-stepper>Labels Only
For text-based navigation without icons:
<ejs-stepper>
<e-steps>
<e-step label="Step 1"></e-step>
<e-step label="Step 2"></e-step>
<e-step label="Step 3"></e-step>
<e-step label="Step 4"></e-step>
</e-steps>
</ejs-stepper>Setting Active Step
Specify the active step by its index using the activeStep property of the Stepper component. The default value is 0. The activeStep property is zero-indexed, so the first step is 0, the second step is 1, and so on.
import { Component } from "@angular/core";
import { StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<div class="stepperIcon">
<ejs-stepper activeStep="1">
<e-steps>
<e-step iconCss="sf-icon-cart"></e-step>
<e-step iconCss="sf-icon-transport"></e-step>
<e-step iconCss="sf-icon-payment"></e-step>
<e-step iconCss="sf-icon-success"></e-step>
</e-steps>
</ejs-stepper>
</div>
`,
styles: [`
.stepperIcon {
padding: 20px;
}
`]
})
export class AppComponent { }Setting Active Step Dynamically
You can also set the active step programmatically using component reference:
@ViewChild('ejStepper') stepper: StepperComponent | any;
setActiveStep(stepIndex: number) {
this.stepper.activeStep = stepIndex;
}Optional Steps
Indicate whether a step is optional using the optional property of the StepModel. By default, the optional property is false. Optional steps are typically displayed with an "Optional" label to indicate that users can skip them if needed.
import { Component } from "@angular/core";
import { StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<div class="stepperOptional">
<ejs-stepper>
<e-steps>
<e-step iconCss="sf-icon-cart" label="Cart"></e-step>
<e-step iconCss="sf-icon-transport" label="Delivery"></e-step>
<e-step iconCss="sf-icon-payment" label="Payment" optional="true"></e-step>
<e-step iconCss="sf-icon-success" label="Confirmation"></e-step>
</e-steps>
</ejs-stepper>
</div>
`,
styles: [`
.stepperOptional {
padding: 20px;
}
`]
})
export class AppComponent { }When to Use Optional Steps
- Upsell steps: Additional optional purchases or features
- Conditional content: Steps that users might not need to complete
- Advanced options: Optional configuration or preferences
- Follow-up actions: Post-purchase or post-completion actions
Disabling Steps
Disable a step to prevent user interaction using the disabled property of the StepModel. Set it to true to disable a step. By default, the value is false.
import { Component } from "@angular/core";
import { StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<div class="stepperWithIcon">
<ejs-stepper>
<e-steps>
<e-step iconCss="sf-icon-cart"></e-step>
<e-step iconCss="sf-icon-transport"></e-step>
<e-step iconCss="sf-icon-payment" disabled="true"></e-step>
<e-step iconCss="sf-icon-success"></e-step>
</e-steps>
</ejs-stepper>
</div>
`,
styles: [`
.stepperWithIcon {
padding: 20px;
}
`]
})
export class AppComponent { }When to Use Disabled Steps
- Dependency-based steps: Steps that depend on earlier steps being completed
- Conditional availability: Steps that don't apply to the current user/workflow
- Prerequisite steps: Steps that require certain conditions to be met
- Gradual rollout: Phased release of new workflow steps
Setting Readonly
Disable user interactions across all steps in the Stepper component using the readOnly property. When set to true, all steps become non-interactive.
import { Component } from "@angular/core";
import { StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<div class="stepperIcon">
<ejs-stepper readOnly="true">
<e-steps>
<e-step iconCss="sf-icon-cart"></e-step>
<e-step iconCss="sf-icon-transport"></e-step>
<e-step iconCss="sf-icon-payment"></e-step>
<e-step iconCss="sf-icon-success"></e-step>
</e-steps>
</ejs-stepper>
</div>
`,
styles: [`
.stepperIcon {
padding: 20px;
}
`]
})
export class AppComponent { }When to Use Readonly
- Review mode: Display completed workflow in read-only mode
- Historical view: Show past process execution without modifications
- View-only display: Display stepper information without allowing changes
- Admin approval mode: Show step information while awaiting approval
Step Status
Specify the progress state of each step using the status property of the StepModel. Possible values are NotStarted, InProgress, and Completed. By default, the value is NotStarted. Status helps users understand the progress and state of each step.
import { Component, ViewChild } from "@angular/core";
import { StepperComponent, StepperChangedEventArgs, StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<div class="stepper-status-section">
<ejs-stepper #ejStepper id="stepper" (stepChanged)="handleStepChanged($event)">
<e-steps>
<e-step iconCss="sf-icon-cart" label="Cart"></e-step>
<e-step iconCss="sf-icon-payment" label="Payment"></e-step>
<e-step iconCss="sf-icon-success" label="Confirmation"></e-step>
</e-steps>
</ejs-stepper>
</div>
<div id="paymentStatus">Your payment has not started yet</div>
`,
styles: [`
.stepper-status-section {
padding: 20px;
}
`]
})
export class AppComponent {
@ViewChild('ejStepper') stepper: StepperComponent | any;
handleStepChanged = (args: StepperChangedEventArgs) => {
let status = this.stepper.steps[1].status
this.updateStatus(status)
}
updateStatus = (stepStatus: string) => {
let statusMap = {
'NotStarted' : { text: 'Your payment has not started yet', color: '#e74d4d' },
'InProgress' : { text: 'Processing your payment', color: 'orange' },
'Completed' : { text: 'Payment successful', color: '#4CAF50' }
}
let currentStatus = document.getElementById("paymentStatus");
if (currentStatus) {
let {text, color } = (statusMap as any)[stepStatus];
currentStatus.innerText = text;
currentStatus.style.backgroundColor = color;
}
}
}Status Types
| Status | Visual Indicator | Meaning |
|---|---|---|
Completed | Checkmark | Step finished successfully |
InProgress | Active indicator | Currently processing |
NotStarted | Neutral | Not yet reached |
Step Validation
Set the validation state for each step to display a success or error icon using the isValid property of the StepModel. When set to true, a success icon appears; when false, an error icon is shown. The default value is null, indicating no validation icon.
Based on the stepType, the validation state icon will be displayed either as an indicator or as part of the step label/text.import { Component } from "@angular/core";
import { StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<div class="stepperWithIconLabel">
<div class="stepper">
<ejs-stepper>
<e-steps>
<e-step iconCss="sf-icon-cart" [isValid]="true"></e-step>
<e-step iconCss="sf-icon-transport"></e-step>
<e-step iconCss="sf-icon-payment" [isValid]="false"></e-step>
<e-step iconCss="sf-icon-success"></e-step>
</e-steps>
</ejs-stepper>
</div>
<div class="labelStepper">
<ejs-stepper>
<e-steps>
<e-step label="Cart" [isValid]="true"></e-step>
<e-step label="Address"></e-step>
<e-step label="Payment" [isValid]="false"></e-step>
<e-step label="Confirmation"></e-step>
</e-steps>
</ejs-stepper>
</div>
</div>
`,
styles: [`
.stepperWithIconLabel {
padding: 20px;
}
`]
})
export class AppComponent { }When to Use Step Validation
- Form validation: Show validation status after form submission
- Multi-step forms: Indicate which steps have validation errors
- Process completion: Display completion status for each step
- Error indication: Show steps with issues or errors
Label Positioning
Configure where step labels are displayed relative to icons and indicators.
Default Label Position
Labels appear below or beside icons depending on stepper orientation:
<ejs-stepper>
<e-steps>
<e-step label="Cart" iconCss="sf-icon-cart"></e-step>
<e-step label="Delivery" iconCss="sf-icon-transport"></e-step>
<e-step label="Payment" iconCss="sf-icon-payment"></e-step>
</e-steps>
</ejs-stepper>Custom Label Styling
Apply custom CSS classes to position and style labels:
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<div class="custom-labels">
<ejs-stepper>
<e-steps>
<e-step label="Personal"
iconCss="sf-icon-profile"
cssClass="custom-step"></e-step>
<e-step label="Address"
iconCss="sf-icon-location"
cssClass="custom-step"></e-step>
<e-step label="Payment"
iconCss="sf-icon-payment"
cssClass="custom-step"></e-step>
</e-steps>
</ejs-stepper>
</div>
`,
styles: [`
.custom-step {
/* Custom styling for label positioning */
}
`]
})
export class AppComponent { }Dynamic Steps
Create steps dynamically from component data:
import { Component } from "@angular/core";
import { StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<ejs-stepper>
<e-steps>
<e-step *ngFor="let step of steps"
[label]="step.label"
[iconCss]="step.icon"></e-step>
</e-steps>
</ejs-stepper>
`
})
export class AppComponent {
steps = [
{ label: 'Cart', icon: 'sf-icon-cart' },
{ label: 'Delivery', icon: 'sf-icon-transport' },
{ label: 'Payment', icon: 'sf-icon-payment' },
{ label: 'Complete', icon: 'sf-icon-success' }
];
}Best Practices
1. Use descriptive labels: Keep labels concise but meaningful 2. Consistent icons: Choose icons that clearly represent each step 3. Icon + label together: Use both for better accessibility and clarity 4. Right icon libraries: Select icon fonts that match your design system 5. Optional steps: Mark optional steps to guide users 6. Disabled steps: Disable steps that require previous step completion
See also: step-types.md for different display styles, orientations-and-layouts.md for layout options.
Templates and Customization in Angular Stepper
Table of Contents
Custom Step Templates
Use Angular's <ng-template> feature to create custom templates for steps. This allows flexible step content with components, forms, or any Angular elements.
Basic Custom Template
import { Component } from "@angular/core";
import { StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
import { CommonModule } from "@angular/common";
@Component({
imports: [ StepperAllModule, StepperModule, CommonModule ],
standalone: true,
selector: 'app-root',
template: `
<div class="template-example">
<ejs-stepper>
<e-steps>
<e-step label="Step 1">
<ng-template #template1>
<div class="custom-content">
<h3>Personal Information</h3>
<form>
<input type="text" placeholder="Full Name">
<input type="email" placeholder="Email">
</form>
</div>
</ng-template>
</e-step>
<e-step label="Step 2">
<ng-template #template2>
<div class="custom-content">
<h3>Address Details</h3>
<form>
<input type="text" placeholder="Street Address">
<input type="text" placeholder="City">
<input type="text" placeholder="Postal Code">
</form>
</div>
</ng-template>
</e-step>
<e-step label="Step 3">
<ng-template #template3>
<div class="custom-content">
<h3>Confirmation</h3>
<p>Review your information above</p>
<button class="confirm-btn">Confirm</button>
</div>
</ng-template>
</e-step>
</e-steps>
</ejs-stepper>
</div>
`,
styles: [`
.template-example {
padding: 20px;
max-width: 700px;
margin: 0 auto;
}
.custom-content {
padding: 20px;
background-color: #fafafa;
border-radius: 4px;
border: 1px solid #ddd;
}
.custom-content h3 {
margin-top: 0;
color: #333;
}
form {
display: flex;
flex-direction: column;
}
input {
margin: 8px 0;
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
}
.confirm-btn {
padding: 10px 20px;
background-color: #4caf50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
margin-top: 10px;
}
`]
})
export class AppComponent { }Template with Components
Embed Angular components within step templates:
<ejs-stepper>
<e-steps>
<e-step label="Payment">
<ng-template #payment>
<app-payment-form (onSubmit)="handlePayment($event)">
</app-payment-form>
</ng-template>
</e-step>
</e-steps>
</ejs-stepper>Template Binding
Bind data to templates using Angular's data binding syntax.
Dynamic Template Content
import { Component } from "@angular/core";
import { StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
import { CommonModule } from "@angular/common";
@Component({
imports: [ StepperAllModule, StepperModule, CommonModule ],
standalone: true,
selector: 'app-root',
template: `
<div class="binding-example">
<ejs-stepper>
<e-steps>
<e-step [label]="'Step ' + (step + 1)"
*ngFor="let step of steps; let i = index">
<ng-template>
<div class="step-item">
<h3>{{ steps[i].title }}</h3>
<p>{{ steps[i].description }}</p>
<div *ngIf="steps[i].items">
<ul>
<li *ngFor="let item of steps[i].items">{{ item }}</li>
</ul>
</div>
</div>
</ng-template>
</e-step>
</e-steps>
</ejs-stepper>
</div>
`,
styles: [`
.binding-example {
padding: 20px;
}
.step-item {
padding: 20px;
background-color: #f5f5f5;
border-radius: 4px;
}
`]
})
export class AppComponent {
steps = [
{
title: 'Setup',
description: 'Configure your application',
items: ['Install dependencies', 'Configure database', 'Set environment']
},
{
title: 'Development',
description: 'Implement features',
items: ['Create components', 'Add business logic', 'Write tests']
},
{
title: 'Deployment',
description: 'Release to production',
items: ['Build application', 'Deploy to server', 'Monitor logs']
}
];
}Two-Way Binding
Use [(ngModel)] for two-way data binding in templates:
<ejs-stepper>
<e-steps>
<e-step label="Personal Info">
<ng-template>
<div class="form-group">
<input type="text"
[(ngModel)]="userData.name"
placeholder="Name">
<input type="email"
[(ngModel)]="userData.email"
placeholder="Email">
<p>Current Name: {{ userData.name }}</p>
</div>
</ng-template>
</e-step>
</e-steps>
</ejs-stepper>Tooltip Templates
Create custom tooltips for steps using templates.
Tooltip Template Example
import { Component } from "@angular/core";
import { StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
import { CommonModule } from "@angular/common";
@Component({
imports: [ StepperAllModule, StepperModule, CommonModule ],
standalone: true,
selector: 'app-root',
template: `
<div class="tooltip-example">
<ejs-stepper [showTooltip]="true">
<e-steps>
<e-step label="Cart" iconCss="sf-icon-cart">
<ng-template #tooltipTemplate>
<div class="tooltip-content">
<strong>Review Items</strong>
<p>Check and modify your selected items</p>
</div>
</ng-template>
</e-step>
<e-step label="Delivery" iconCss="sf-icon-transport">
<ng-template #tooltipTemplate>
<div class="tooltip-content">
<strong>Shipping Details</strong>
<p>Enter your delivery address</p>
</div>
</ng-template>
</e-step>
<e-step label="Payment" iconCss="sf-icon-payment">
<ng-template #tooltipTemplate>
<div class="tooltip-content">
<strong>Payment Information</strong>
<p>Provide payment method details</p>
</div>
</ng-template>
</e-step>
</e-steps>
</ejs-stepper>
</div>
`,
styles: [`
.tooltip-example {
padding: 20px;
}
.tooltip-content {
padding: 10px;
}
.tooltip-content strong {
display: block;
margin-bottom: 5px;
}
.tooltip-content p {
margin: 0;
font-size: 12px;
}
`]
})
export class AppComponent { }CSS Class Customization
Apply custom CSS classes to steps for styling and layout control.
Using CSS Classes
import { Component } from "@angular/core";
import { StepperAllModule, StepperModule } from "@syncfusion/ej2-angular-navigations";
@Component({
imports: [ StepperAllModule, StepperModule ],
standalone: true,
selector: 'app-root',
template: `
<div class="css-class-example">
<ejs-stepper>
<e-steps>
<e-step label="Step 1"
iconCss="sf-icon-cart"
cssClass="primary-step"></e-step>
<e-step label="Step 2"
iconCss="sf-icon-transport"
cssClass="secondary-step"></e-step>
<e-step label="Step 3"
iconCss="sf-icon-payment"
cssClass="attention-step"></e-step>
</e-steps>
</ejs-stepper>
</div>
`,
styles: [`
.css-class-example {
padding: 20px;
}
/* Primary step styling */
:deep(.primary-step) {
color: #1976d2;
}
/* Secondary step styling */
:deep(.secondary-step) {
color: #757575;
}
/* Attention step with special styling */
:deep(.attention-step) {
color: #f57c00;
font-weight: bold;
}
`]
})
export class AppComponent { }Layout Customization
Customize the stepper layout to fit different UI patterns.
Full-Width Stepper
<div class="full-width-stepper">
<ejs-stepper [orientation]="'Horizontal'">
<e-steps>
<e-step label="Step 1"></e-step>
<e-step label="Step 2"></e-step>
<e-step label="Step 3"></e-step>
<e-step label="Step 4"></e-step>
</e-steps>
</ejs-stepper>
</div>
<style>
.full-width-stepper {
width: 100%;
}
</style>Card-Based Layout
@Component({
template: `
<div class="card-layout">
<div class="card">
<ejs-stepper>
<e-steps>
<e-step label="Card Step 1"></e-step>
<e-step label="Card Step 2"></e-step>
<e-step label="Card Step 3"></e-step>
</e-steps>
</ejs-stepper>
</div>
</div>
`,
styles: [`
.card-layout {
padding: 20px;
}
.card {
background: white;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
padding: 20px;
}
`]
})
export class AppComponent { }Flexible Sidebar Layout
@Component({
template: `
<div class="flex-layout">
<aside class="sidebar">
<ejs-stepper orientation="Vertical">
<e-steps>
<e-step label="Section 1"></e-step>
<e-step label="Section 2"></e-step>
<e-step label="Section 3"></e-step>
</e-steps>
</ejs-stepper>
</aside>
<main class="content">
<!-- Main content here -->
</main>
</div>
`,
styles: [`
.flex-layout {
display: flex;
gap: 20px;
}
.sidebar {
flex: 0 0 250px;
padding: 20px;
background-color: #f5f5f5;
border-radius: 4px;
}
.content {
flex: 1;
padding: 20px;
}
`]
})
export class AppComponent { }Styling Patterns
Theme Customization
/* Override Syncfusion theme colors */
:deep(.e-stepper) {
--primary-color: #1976d2;
--secondary-color: #f57c00;
--success-color: #4caf50;
--error-color: #f44336;
}
/* Custom step indicator styling */
:deep(.e-step-indicator) {
width: 40px;
height: 40px;
border-radius: 50%;
}
/* Custom label styling */
:deep(.e-step-label-container) {
font-weight: 500;
font-size: 14px;
}Responsive Styling
/* Desktop - Horizontal layout */
@media (min-width: 1024px) {
:deep(.e-stepper) {
flex-direction: row;
}
}
/* Tablet - Transitional layout */
@media (max-width: 768px) {
:deep(.e-stepper) {
flex-direction: column;
}
}
/* Mobile - Vertical compact layout */
@media (max-width: 480px) {
:deep(.e-step-label-container) {
display: none;
}
:deep(.e-stepper) {
gap: 8px;
}
}Best Practices
1. Templates for complexity: Use templates for rich content beyond simple labels 2. Reusable components: Create step content as separate components 3. Clear CSS naming: Use descriptive class names 4. Responsive design: Test on multiple screen sizes 5. Performance: Avoid heavy operations in templates 6. Accessibility: Ensure templates include proper ARIA labels
See also: getting-started.md for basic setup, step-types.md for display options.