Skip to main content
The CDK stepper allows you to build a custom stepper which you can completely style yourself without any specific Material Design styling.

Overview

In this guide, we’ll learn how to build our own custom stepper using the CDK stepper. This approach gives you complete control over the appearance and behavior of your stepper.

Create the Custom Stepper Component

1

Extend CdkStepper

Create a new Angular component that extends CdkStepper:
@Component({
  selector: 'app-custom-stepper',
  templateUrl: './custom-stepper.component.html',
  styleUrl: './custom-stepper.component.css',
  // This custom stepper provides itself as CdkStepper so that it can be recognized
  // by other components.
  providers: [{ provide: CdkStepper, useExisting: CustomStepperComponent }]
})
export class CustomStepperComponent extends CdkStepper {
  onClick(index: number): void {
    this.selectedIndex = index;
  }
}
After extending CdkStepper, you can access properties like linear, selectedIndex, and steps from the base class.
2

Create the template

Design the HTML template for your custom stepper:
<section class="container">
  <header><h2>Step {{selectedIndex + 1}}/{{steps.length}}</h2></header>

  <div [style.display]="selected ? 'block' : 'none'">
    <!-- Content from the CdkStep is projected here -->
    <ng-container [ngTemplateOutlet]="selected.content"></ng-container>
  </div>

  <footer class="step-navigation-bar">
    <button class="nav-button" cdkStepperPrevious>&larr;</button>
    @for (step of steps; track step; let i = $index) {
      <button class="step" [class.active]="selectedIndex === i" (click)="onClick(i)">
        Step {{i + 1}}
      </button>
    }
    <button class="nav-button" cdkStepperNext>&rarr;</button>
  </footer>
</section>
3

Add custom styles

Style the stepper however you want:
.example-container {
  border: 1px solid black;
  padding: 10px;
  margin: 10px;
}

.example-step-navigation-bar {
  display: flex;
  justify-content: flex-start;
  margin-top: 10px;
}

.example-step {
  background: transparent;
  border: 0;
  margin: 0 10px;
  padding: 10px;
  color: black;
}

.example-step.example-active {
  color: blue;
  border-bottom: 1px solid blue;
}

.example-nav-button {
  background: transparent;
  border: 0;
}

Using the Custom Stepper

Now you can use your custom stepper component and fill it with steps:
<app-custom-stepper>
  <cdk-step><p>This is any content of "Step 1"</p></cdk-step>
  <cdk-step><p>This is any content of "Step 2"</p></cdk-step>
</app-custom-stepper>
Each step needs to be wrapped inside a <cdk-step> tag.

Linear Mode

The CdkStepper provides linear mode which requires the user to complete previous steps before proceeding.

Example Without Forms

<app-custom-stepper linear>
  <cdk-step editable="false" [completed]="completed">
    <input type="text" name="a" value="Cannot proceed to next step" />
    <button (click)="completeStep()">Complete step</button>
  </cdk-step>
  <cdk-step editable="false">
    <input type="text" name="b" value="b" />
  </cdk-step>
</app-custom-stepper>
export class AppComponent {
  completed = false;

  completeStep(): void {
    this.completed = true;
  }
}
In linear mode, users cannot navigate to subsequent steps until the current step is marked as completed.

Key Features

The CDK stepper provides built-in directives for navigation:
  • cdkStepperPrevious - Navigate to the previous step
  • cdkStepperNext - Navigate to the next step
Control step behavior using:
  • selectedIndex - Get or set the current step
  • linear - Enable sequential step validation
  • completed - Mark a step as completed
  • editable - Allow returning to completed steps
Use ng-content or ngTemplateOutlet to project custom content into each step.

API Documentation

For detailed information about available properties and methods, see the CDK Stepper API documentation.

Custom Form Field

Create custom form controls

Theming

Style your components

Build docs developers (and LLMs) love