Stepper

The stepper component is to guide through multiple steps. The steps are indicated by the progress indicator on the top. There should be at least 3 steps.

The stepper component creates a multi step workflow by creating a content area for each step provided.

´ Loading interactive demo...
<dt-stepper #stepper linear> <dt-step label="Type"> <h2>What type of synthetic monitor do you want to create?</h2> <div class="monitor-type-wrapper"> <div class="monitor-type"> <img src="/assets/browser-monitor.svg" alt="Browser monitor" /> <h3>Simulate user behavior in a real browser</h3> <p> A browser monitor is a simulated user session driven by a modern web browser. You can either monitor a URL or record a sequence of clicks and user input that should be replayed during monitoring. </p> <button variant="secondary" dt-button dtStepperNext> Create a browser monitor </button> </div> <div class="monitor-type"> <img src="/assets/http-monitor.svg" alt="HTTP monitor" /> <h3>Create a basic HTTP monitor</h3> <p> An HTTP monitor uses a simple HTTP request to monitor the availability of a URL used by your application. </p> <button variant="secondary" dt-button dtStepperNext> Create an HTTP monitor </button> </div> </div> </dt-step> <dt-step [stepControl]="configurationFormGroup" label="Configuration"> <form [formGroup]="configurationFormGroup"> <dt-form-field> <dt-label>Name this monitor</dt-label> <input dtInput placeholder="For example, mysite" formControlName="nameCtrl" required /> <dt-error>This field cannot be empty.</dt-error> </dt-form-field> <dt-step-actions> <button dt-button dtStepperPrevious>Previous</button> <button dt-button dtStepperNext>Next</button> </dt-step-actions> </form> </dt-step> <dt-step label="Frequency and locations"> <h2>Frequency and locations</h2> <dt-form-field> <dt-label>Website monitor interval</dt-label> <dt-select value="15"> <dt-option value="15">15 min</dt-option> <dt-option value="30">30 min</dt-option> <dt-option value="45">45 min</dt-option> </dt-select> </dt-form-field> <dt-step-actions> <button dt-button dtStepperPrevious>Previous</button> <button dt-button dtStepperNext>Next</button> </dt-step-actions> </dt-step> <dt-step> <ng-template dtStepLabel>Summary</ng-template> <p>Finished!</p> <dt-step-actions> <button variant="secondary" dt-button dtStepperPrevious> Previous </button> <button dt-button (click)="stepper.reset()">Reset stepper</button> </dt-step-actions> </dt-step> </dt-stepper> export class StepperDefaultExample implements OnInit { @ViewChild(DtStepper, { static: true }) stepper: DtStepper; configurationFormGroup: FormGroup; constructor(private _formBuilder: FormBuilder) {} ngOnInit(): void { this.configurationFormGroup = this._formBuilder.group({ // tslint:disable-next-line: no-unbound-method nameCtrl: ['', Validators.required], }); } } <dt-stepper #stepper linear> <dt-step label="Type"> <h2>What type of synthetic monitor do you want to create?</h2> <div class="monitor-type-wrapper"> <div class="monitor-type"> <img src="/assets/browser-monitor.svg" alt="Browser monitor" /> <h3>Simulate user behavior in a real browser</h3> <p> A browser monitor is a simulated user session driven by a modern web browser. You can either monitor a URL or record a sequence of clicks and user input that should be replayed during monitoring. </p> <button variant="secondary" dt-button dtStepperNext> Create a browser monitor </button> </div> <div class="monitor-type"> <img src="/assets/http-monitor.svg" alt="HTTP monitor" /> <h3>Create a basic HTTP monitor</h3> <p> An HTTP monitor uses a simple HTTP request to monitor the availability of a URL used by your application. </p> <button variant="secondary" dt-button dtStepperNext> Create an HTTP monitor </button> </div> </div> </dt-step> <dt-step [stepControl]="configurationFormGroup" label="Configuration"> <form [formGroup]="configurationFormGroup"> <dt-form-field> <dt-label>Name this monitor</dt-label> <input dtInput placeholder="For example, mysite" formControlName="nameCtrl" required /> <dt-error>This field cannot be empty.</dt-error> </dt-form-field> <dt-step-actions> <button dt-button dtStepperPrevious>Previous</button> <button dt-button dtStepperNext>Next</button> </dt-step-actions> </form> </dt-step> <dt-step label="Frequency and locations"> <h2>Frequency and locations</h2> <dt-form-field> <dt-label>Website monitor interval</dt-label> <dt-select value="15"> <dt-option value="15">15 min</dt-option> <dt-option value="30">30 min</dt-option> <dt-option value="45">45 min</dt-option> </dt-select> </dt-form-field> <dt-step-actions> <button dt-button dtStepperPrevious>Previous</button> <button dt-button dtStepperNext>Next</button> </dt-step-actions> </dt-step> <dt-step> <ng-template dtStepLabel>Summary</ng-template> <p>Finished!</p> <dt-step-actions> <button variant="secondary" dt-button dtStepperPrevious> Previous </button> <button dt-button (click)="stepper.reset()">Reset stepper</button> </dt-step-actions> </dt-step> </dt-stepper> export class StepperDefaultExample implements OnInit { @ViewChild(DtStepper, { static: true }) stepper: DtStepper; configurationFormGroup: FormGroup; constructor(private _formBuilder: FormBuilder) {} ngOnInit(): void { this.configurationFormGroup = this._formBuilder.group({ // tslint:disable-next-line: no-unbound-method nameCtrl: ['', Validators.required], }); } }

A step can have multiple states during the workflow. One step at a time can be selected. Steps can be active or inactive depending if they were interacted with in the past. If a step has a stepControl associated, the step gets completed as soon as the stepControl is valid. Otherwise a step becomes completed as soon as it becomes active.

Imports

You have to import the DtStepperModule when you want to use the dt-stepper and the dt-step:

@NgModule({
  imports: [DtStepperModule],
})
class MyModule {}

Initialization

To use the stepper component add the dt-stepper component and multiple dt-step components as content children to the dt-stepper.

DtStepper

The dt-stepper component handles which step is active and therefore what content needs to be shown. It also handles correct keyboard and focus management for the steps. By default the steps don't have to be completed in order. This can be changed by setting the linear Input to true. You have two options to handle validation for steps. You can use a single form for all steps - note that you have to set the type Input on the dtStepperNext and dtStepperPrevious directives to button. Otherwise the form gets submitted on the first click. When using multiple forms the validity of each form can used to validate the step's completion status. You can attach the form to the step by passing the formControl to the stepControl Input on the step.

Inputs

Name Type Default Description
linear boolean false Whether the user can continue to the next step even if the current step is not completed
selected DtStep The step that is selected
selectedIndex number The index of the selected step

Outputs

Name Type Description
selectionChange EventEmitter<StepperSelectionEvent> Event emitted when the selected step changed

Methods

Name Return value Description
next void Selects and focuses the next step
previous void Selects and focuses the previous step
reset void Resets the stepper to it's initial state

DtStep

With the dt-step component you can create a step inside the stepper. You can provide the content that will be shown when the step is active as ng-content between the tags of the dt-step. If the dt-stepper is set to linear, each step has to be completed before advancing to the next step. If this is not desired for a step, the optional Input can be used and set to false to make a step optional. Steps that are set to editable by the editable Input can be changed after they are set to completed.

Inputs

Name Type Default Description
aria-label string The aria label used for the step
aria-labelledby string The id of the element the step is labelled by
completed boolean false Whether the step is completed
editable boolean true Whether a user can return to an already completed step
label string A string only label used for the step
completed boolean false Whether the step is completed
optional boolean false Whether completion of the step is optional
state StepState 'number' | 'edit' | 'done' | 'error' | string State of the step
stepControl FormControlLike Control of the step that is used to validate completion

Methods

Name Return value Description
select void Selects the step
reset void Resets the step to it's initial state

For complex step labels we provide a directive dtStepLabel that can be used to specify a label that contains markdown.

<dt-step>
<ng-template dtStepLabel>My label with an icon <dt-icon name="agent"></dt-icon></ng-template>
</dt-step>

To apply the proper spacing, alignment and behaviour for next and previous buttons for the stepper there are a couple of directives that you can use.

DtStepActions

You can use the dt-step-actions directive in your template to group the next and previous buttons and align them correctly.

DtStepperPrevious & DtStepperNext

The dtStepperPrevious and dtStepperNext directives can be applied to dt-button elements and provide an easy way to handle the transition from one step to another in the workflow. These two directives default the type of the button to submit.

Stepper in use

Linear stepper

A stepper that is set to be linear. So each step has to be valid before the next step can be activated.

´ Loading interactive demo...
<dt-checkbox [checked]="isLinear" (change)="isLinear = !isLinear"> linear steps </dt-checkbox> <dt-stepper #stepper [linear]="isLinear"> <dt-step [stepControl]="firstFormGroup"> <form [formGroup]="firstFormGroup"> <ng-template dtStepLabel >Fill out your name Fill out your name Fill out your name Fill out your name</ng-template > <dt-form-field> <dt-label>Name</dt-label> <input dtInput formControlName="firstCtrl" required /> <dt-error>Name is required</dt-error> </dt-form-field> <dt-step-actions> <button dt-button dtStepperNext>Next</button> </dt-step-actions> </form> </dt-step> <dt-step [stepControl]="secondFormGroup"> <form [formGroup]="secondFormGroup"> <ng-template dtStepLabel>Fill out your address</ng-template> <dt-form-field> <dt-label>Address</dt-label> <input dtInput formControlName="secondCtrl" required /> <dt-error>Address is required</dt-error> </dt-form-field> <dt-step-actions> <button dt-button variant="secondary" dtStepperPrevious> Back </button> <button dt-button dtStepperNext>Next</button> </dt-step-actions> </form> </dt-step> <dt-step> <ng-template dtStepLabel>Step 3</ng-template> <p>Finished!</p> <dt-step-actions> <button dt-button variant="secondary" (click)="stepper.previous()"> Previous </button> <button dt-button (click)="stepper.reset()">Reset stepper</button> </dt-step-actions> </dt-step> </dt-stepper> export class StepperLinearExample implements OnInit { firstFormGroup: FormGroup; secondFormGroup: FormGroup; isLinear = true; constructor(private _formBuilder: FormBuilder) {} ngOnInit(): void { this.firstFormGroup = this._formBuilder.group({ // tslint:disable-next-line: no-unbound-method firstCtrl: ['', Validators.required], }); this.secondFormGroup = this._formBuilder.group({ // tslint:disable-next-line: no-unbound-method secondCtrl: ['', Validators.required], }); } } <dt-checkbox [checked]="isLinear" (change)="isLinear = !isLinear"> linear steps </dt-checkbox> <dt-stepper #stepper [linear]="isLinear"> <dt-step [stepControl]="firstFormGroup"> <form [formGroup]="firstFormGroup"> <ng-template dtStepLabel >Fill out your name Fill out your name Fill out your name Fill out your name</ng-template > <dt-form-field> <dt-label>Name</dt-label> <input dtInput formControlName="firstCtrl" required /> <dt-error>Name is required</dt-error> </dt-form-field> <dt-step-actions> <button dt-button dtStepperNext>Next</button> </dt-step-actions> </form> </dt-step> <dt-step [stepControl]="secondFormGroup"> <form [formGroup]="secondFormGroup"> <ng-template dtStepLabel>Fill out your address</ng-template> <dt-form-field> <dt-label>Address</dt-label> <input dtInput formControlName="secondCtrl" required /> <dt-error>Address is required</dt-error> </dt-form-field> <dt-step-actions> <button dt-button variant="secondary" dtStepperPrevious> Back </button> <button dt-button dtStepperNext>Next</button> </dt-step-actions> </form> </dt-step> <dt-step> <ng-template dtStepLabel>Step 3</ng-template> <p>Finished!</p> <dt-step-actions> <button dt-button variant="secondary" (click)="stepper.previous()"> Previous </button> <button dt-button (click)="stepper.reset()">Reset stepper</button> </dt-step-actions> </dt-step> </dt-stepper> export class StepperLinearExample implements OnInit { firstFormGroup: FormGroup; secondFormGroup: FormGroup; isLinear = true; constructor(private _formBuilder: FormBuilder) {} ngOnInit(): void { this.firstFormGroup = this._formBuilder.group({ // tslint:disable-next-line: no-unbound-method firstCtrl: ['', Validators.required], }); this.secondFormGroup = this._formBuilder.group({ // tslint:disable-next-line: no-unbound-method secondCtrl: ['', Validators.required], }); } }

Editable steps

A stepper where steps can be edited after they have been completed.

´ Loading interactive demo...
<dt-checkbox [checked]="isEditable" (change)="isEditable = !isEditable"> editable steps </dt-checkbox> <dt-stepper #stepper linear> <dt-step [stepControl]="firstFormGroup" [editable]="isEditable"> <form [formGroup]="firstFormGroup"> <ng-template dtStepLabel>Fill out your name</ng-template> <dt-form-field> <dt-label>Name</dt-label> <input dtInput formControlName="firstCtrl" required /> <dt-error>Name is required</dt-error> </dt-form-field> <dt-step-actions> <button dt-button dtStepperNext>Next</button> </dt-step-actions> </form> </dt-step> <dt-step [stepControl]="secondFormGroup" [editable]="isEditable"> <form [formGroup]="secondFormGroup"> <ng-template dtStepLabel>Fill out your address</ng-template> <dt-form-field> <dt-label>Address</dt-label> <input dtInput formControlName="secondCtrl" required /> <dt-error>Address is required</dt-error> </dt-form-field> <dt-step-actions> <button dt-button dtStepperPrevious *ngIf="isEditable">Back</button> <button dt-button dtStepperNext>Next</button> </dt-step-actions> </form> </dt-step> <dt-step> <ng-template dtStepLabel>Step 3</ng-template> <p>Finished!</p> <dt-step-actions> <button variant="secondary" (click)="stepper.previous()" dt-button> Previous </button> <button dt-button (click)="stepper.reset()">Reset stepper</button> </dt-step-actions> </dt-step> </dt-stepper> export class StepperEditableExample implements OnInit { firstFormGroup: FormGroup; secondFormGroup: FormGroup; isEditable = false; constructor(private _formBuilder: FormBuilder) {} ngOnInit(): void { this.firstFormGroup = this._formBuilder.group({ // tslint:disable-next-line: no-unbound-method firstCtrl: ['', Validators.required], }); this.secondFormGroup = this._formBuilder.group({ // tslint:disable-next-line: no-unbound-method secondCtrl: ['', Validators.required], }); } } <dt-checkbox [checked]="isEditable" (change)="isEditable = !isEditable"> editable steps </dt-checkbox> <dt-stepper #stepper linear> <dt-step [stepControl]="firstFormGroup" [editable]="isEditable"> <form [formGroup]="firstFormGroup"> <ng-template dtStepLabel>Fill out your name</ng-template> <dt-form-field> <dt-label>Name</dt-label> <input dtInput formControlName="firstCtrl" required /> <dt-error>Name is required</dt-error> </dt-form-field> <dt-step-actions> <button dt-button dtStepperNext>Next</button> </dt-step-actions> </form> </dt-step> <dt-step [stepControl]="secondFormGroup" [editable]="isEditable"> <form [formGroup]="secondFormGroup"> <ng-template dtStepLabel>Fill out your address</ng-template> <dt-form-field> <dt-label>Address</dt-label> <input dtInput formControlName="secondCtrl" required /> <dt-error>Address is required</dt-error> </dt-form-field> <dt-step-actions> <button dt-button dtStepperPrevious *ngIf="isEditable">Back</button> <button dt-button dtStepperNext>Next</button> </dt-step-actions> </form> </dt-step> <dt-step> <ng-template dtStepLabel>Step 3</ng-template> <p>Finished!</p> <dt-step-actions> <button variant="secondary" (click)="stepper.previous()" dt-button> Previous </button> <button dt-button (click)="stepper.reset()">Reset stepper</button> </dt-step-actions> </dt-step> </dt-stepper> export class StepperEditableExample implements OnInit { firstFormGroup: FormGroup; secondFormGroup: FormGroup; isEditable = false; constructor(private _formBuilder: FormBuilder) {} ngOnInit(): void { this.firstFormGroup = this._formBuilder.group({ // tslint:disable-next-line: no-unbound-method firstCtrl: ['', Validators.required], }); this.secondFormGroup = this._formBuilder.group({ // tslint:disable-next-line: no-unbound-method secondCtrl: ['', Validators.required], }); } }