Stepper
Use cases:
- Provide a multi-step process or dynamic form that the user can follow.
- Validate step by step before the user can move on through the workflow.
Rapid Stepper requires rapid-stepper-tab
and rapid-stepper-tab-panel
in order to work properly.
The order of the rapid-stepper-tab corresponds to the order of the rapid-stepper-tab-panel.
Example
- Genesis
- React
- Angular
Declaration
<rapid-stepper>
<rapid-stepper-tab>Step 1</rapid-stepper-tab>
<rapid-stepper-tab>Step 2</rapid-stepper-tab>
<rapid-stepper-tab>Step 3</rapid-stepper-tab>
<rapid-stepper-tab-panel>
Tab Panel 1
</rapid-stepper-tab-panel>
<rapid-stepper-tab-panel>
Tab Panel 2
</rapid-stepper-tab-panel>
<rapid-stepper-tab-panel>
Tab Panel 3
</rapid-stepper-tab-panel>
</rapid-stepper>
Usage
@customElement({
name: 'my-element',
template: html`
<rapid-stepper @submit="${(x) => x.handleSubmit()}">
<rapid-stepper-tab>Step 1</rapid-stepper-tab>
<rapid-stepper-tab>Step 2</rapid-stepper-tab>
<rapid-stepper-tab>Step 3</rapid-stepper-tab>
<rapid-stepper-tab-panel>
Tab Panel 1
</rapid-stepper-tab-panel>
<rapid-stepper-tab-panel>
Tab Panel 2
</rapid-stepper-tab-panel>
<rapid-stepper-tab-panel>
Tab Panel 3
</rapid-stepper-tab-panel>
</rapid-stepper>
`,
})
export class MyElement extends GenesisElement {
@observable radioValue: string;
handleSubmit() {
console.log('Form submitted');
}
}
Declaration
<rapid-stepper>
<rapid-stepper-tab>Step 1</rapid-stepper-tab>
<rapid-stepper-tab>Step 2</rapid-stepper-tab>
<rapid-stepper-tab>Step 3</rapid-stepper-tab>
<rapid-stepper-tab-panel>
Tab Panel 1
</rapid-stepper-tab-panel>
<rapid-stepper-tab-panel>
Tab Panel 2
</rapid-stepper-tab-panel>
<rapid-stepper-tab-panel>
Tab Panel 3
</rapid-stepper-tab-panel>
</rapid-stepper>
Usage
export function MyComponent() {
const handleSubmit = (event) => {
console.log('Form submitted');
};
return (
<rapid-stepper onSubmit={handleSubmit}>
<rapid-stepper-tab>Step 1</rapid-stepper-tab>
<rapid-stepper-tab>Step 2</rapid-stepper-tab>
<rapid-stepper-tab>Step 3</rapid-stepper-tab>
<rapid-stepper-tab-panel>
Tab Panel 1
</rapid-stepper-tab-panel>
<rapid-stepper-tab-panel>
Tab Panel 2
</rapid-stepper-tab-panel>
<rapid-stepper-tab-panel>
Tab Panel 3
</rapid-stepper-tab-panel>
</rapid-stepper>
);
}
Declaration
<rapid-stepper>
<rapid-stepper-tab>Step 1</rapid-stepper-tab>
<rapid-stepper-tab>Step 2</rapid-stepper-tab>
<rapid-stepper-tab>Step 3</rapid-stepper-tab>
<rapid-stepper-tab-panel>
Tab Panel 1
</rapid-stepper-tab-panel>
<rapid-stepper-tab-panel>
Tab Panel 2
</rapid-stepper-tab-panel>
<rapid-stepper-tab-panel>
Tab Panel 3
</rapid-stepper-tab-panel>
</rapid-stepper>
Usage
import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
@Component({
selector: 'my-root',
template: `
<rapid-stepper (submit)="handleSubmit($event)">
<rapid-stepper-tab>Step 1</rapid-stepper-tab>
<rapid-stepper-tab>Step 2</rapid-stepper-tab>
<rapid-stepper-tab>Step 3</rapid-stepper-tab>
<rapid-stepper-tab-panel>
Tab Panel 1
</rapid-stepper-tab-panel>
<rapid-stepper-tab-panel>
Tab Panel 2
</rapid-stepper-tab-panel>
<rapid-stepper-tab-panel>
Tab Panel 3
</rapid-stepper-tab-panel>
</rapid-stepper>
`,
standalone: true,
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppComponent {
handleSubmit(event: Event) {
console.log('Form submitted');
}
}
API
Property and attribute binding examples for Genesis Component syntax.
Attributes
Name | Type | Description | Examples |
---|---|---|---|
hide-submit-button | boolean | Hides or shows the submit button |
|
orientation | string | There are two stepper orientations to choose from: vertical and horizontal. |
|
hide-all-buttons | boolean | Hides all navigation buttons (Back, Next, Submit) |
|
hide-step-number | boolean | Hides the step number display in the stepper tabs |
|
allow-backward-jumps | boolean | Allows users to click on previous steps to navigate backwards |
|
allow-forward-jumps | boolean | Allows users to click on future steps to navigate forwards (with validation) |
|
Properties
Name | Type | Description | Examples |
---|---|---|---|
validation |
| If set, the predicate function defined at index x is executed to check whether step x is valid when trying to move onto the subsequent step.
If the predicate returns false the stepper will not move to the next step. See this example. |
|
Methods
Name | Parameters | Return Type | Description | Examples |
---|---|---|---|---|
goToStep | stepNumber: number, bypassJumpRestrictions?: boolean | boolean | Go to a specific step by step number (1-based indexing). Returns true if successful, false if step number is invalid or already on that step. |
|
goToFirstStep | None | boolean | Go to the first step (step 1). Returns true if successful, false if already on first step. |
|
goToLastStep | None | boolean | Go to the last step. Returns true if successful, false if already on last step. |
|
Slots
Slot |
---|
tab |
tab-panel |
action-buttons |
Parts
Part |
---|
stepper-tab |
stepper-tab-menu |
stepper-tab-progress |
progress-ring |
stepper-tab-panel |
stepper-panel-container |
action-buttons-container |
Events fired
Name | Type | Description | Example |
---|---|---|---|
@submit | void | Enables you to pass the function to be performed in the last step after clicking submit. |
|
@step-click | {activetab: HTMLElement, activeid: string} | Fired when a step is clicked and navigation occurs. |
|
@validation-failure | {stepIndex: number, stepId: string, message: string} | Fired when validation fails during forward jumps. |
|
@next-step | void | Fired when moving to the next step. |
|
@validation-success | void | Fired when validation passes during step navigation. |
|
Events listened to
This component doesn't listen to any events.
Advanced concepts
Validation
Use the validation field to set the condition for when the stepper permits the user to move forward.
You define the validation attribute as follows:
- Genesis
- React
- Angular
const template = html`
<rapid-stepper
:validation=${(x) => [
{
isValid: () => x.valid === '123' && x.valid2 === 'abc' && x.valid3 === 'test',
},
{ isValid: () => x.valid4 === 'abc' },
{ isValid: () => x.valid5 === 'finish' },
]}
@submit=${() => alert('You completed form')}
>
<rapid-stepper-tab>Step 1</rapid-stepper-tab>
<rapid-stepper-tab>Step 2</rapid-stepper-tab>
<rapid-stepper-tab>Step 3</rapid-stepper-tab>
<rapid-stepper-tab-panel>
<rapid-text-field style="margin-left: 10px;" value=${sync((x) => x.valid)}>
Must be equal to: 123
</rapid-text-field>
<rapid-text-field style="margin-left: 10px;" value=${sync((x) => x.valid2)}>
Must be equal to: abc
</rapid-text-field>
<rapid-text-field style="margin-left: 10px;" value=${sync((x) => x.valid3)}>
Must be equal to: test
</rapid-text-field>
</rapid-stepper-tab-panel>
<rapid-stepper-tab-panel>
<h5>Must be equal to: abc</h5>
<rapid-select style="margin: 10px 0 0 10px;" :value=${sync((x) => x.valid4)}>
<rapid-option>123</rapid-option>
<rapid-option>abc</rapid-option>
</rapid-select>
</rapid-stepper-tab-panel>
<rapid-stepper-tab-panel>
<rapid-text-field style="margin-left: 10px;" value=${sync((x) => x.valid5)}>
Must be equal to: finish
</rapid-text-field>
</rapid-stepper-tab-panel>
</rapid-stepper>
`;
import React, { useState } from 'react';
export function StepperValidationExample() {
const [valid, setValid] = useState('');
const [valid2, setValid2] = useState('');
const [valid3, setValid3] = useState('');
const [valid4, setValid4] = useState('');
const [valid5, setValid5] = useState('');
const validationConfig = [
{
isValid: () => valid === '123' && valid2 === 'abc' && valid3 === 'test',
},
{ isValid: () => valid4 === 'abc' },
{ isValid: () => valid5 === 'finish' },
];
const handleSubmit = () => {
alert('You completed form');
};
return (
<rapid-stepper
validation={validationConfig}
onSubmit={handleSubmit}
>
<rapid-stepper-tab>Step 1</rapid-stepper-tab>
<rapid-stepper-tab>Step 2</rapid-stepper-tab>
<rapid-stepper-tab>Step 3</rapid-stepper-tab>
<rapid-stepper-tab-panel>
<rapid-text-field
style={{marginLeft: '10px'}}
value={valid}
onChange={(e) => setValid(e.target.value)}
>
Must be equal to: 123
</rapid-text-field>
<rapid-text-field
style={{marginLeft: '10px'}}
value={valid2}
onChange={(e) => setValid2(e.target.value)}
>
Must be equal to: abc
</rapid-text-field>
<rapid-text-field
style={{marginLeft: '10px'}}
value={valid3}
onChange={(e) => setValid3(e.target.value)}
>
Must be equal to: test
</rapid-text-field>
</rapid-stepper-tab-panel>
<rapid-stepper-tab-panel>
<h5>Must be equal to: abc</h5>
<rapid-select
style={{margin: '10px 0 0 10px'}}
value={valid4}
onChange={(e) => setValid4(e.target.value)}
>
<rapid-option>123</rapid-option>
<rapid-option>abc</rapid-option>
</rapid-select>
</rapid-stepper-tab-panel>
<rapid-stepper-tab-panel>
<rapid-text-field
style={{marginLeft: '10px'}}
value={valid5}
onChange={(e) => setValid5(e.target.value)}
>
Must be equal to: finish
</rapid-text-field>
</rapid-stepper-tab-panel>
</rapid-stepper>
);
}
import { Component } from '@angular/core';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
@Component({
selector: 'stepper-validation-example',
template: `
<rapid-stepper
[validation]="validationConfig"
(submit)="handleSubmit($event)"
>
<rapid-stepper-tab>Step 1</rapid-stepper-tab>
<rapid-stepper-tab>Step 2</rapid-stepper-tab>
<rapid-stepper-tab>Step 3</rapid-stepper-tab>
<rapid-stepper-tab-panel>
<rapid-text-field
style="margin-left: 10px;"
[value]="valid"
(change)="valid = $event.target.value"
>
Must be equal to: 123
</rapid-text-field>
<rapid-text-field
style="margin-left: 10px;"
[value]="valid2"
(change)="valid2 = $event.target.value"
>
Must be equal to: abc
</rapid-text-field>
<rapid-text-field
style="margin-left: 10px;"
[value]="valid3"
(change)="valid3 = $event.target.value"
>
Must be equal to: test
</rapid-text-field>
</rapid-stepper-tab-panel>
<rapid-stepper-tab-panel>
<h5>Must be equal to: abc</h5>
<rapid-select
style="margin: 10px 0 0 10px;"
[value]="valid4"
(change)="valid4 = $event.target.value"
>
<rapid-option>123</rapid-option>
<rapid-option>abc</rapid-option>
</rapid-select>
</rapid-stepper-tab-panel>
<rapid-stepper-tab-panel>
<rapid-text-field
style="margin-left: 10px;"
[value]="valid5"
(change)="valid5 = $event.target.value"
>
Must be equal to: finish
</rapid-text-field>
</rapid-stepper-tab-panel>
</rapid-stepper>
`,
standalone: true,
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class StepperValidationExampleComponent {
valid = '';
valid2 = '';
valid3 = '';
valid4 = '';
valid5 = '';
validationConfig = [
{
isValid: () => this.valid === '123' && this.valid2 === 'abc' && this.valid3 === 'test',
},
{ isValid: () => this.valid4 === 'abc' },
{ isValid: () => this.valid5 === 'finish' },
];
handleSubmit(event: Event) {
alert('You completed form');
}
}
The index of each array element is related to the corresponding tab position. Index number 0 is related to the first tab of the stepper, index number 1 is related to the second tab of the stepper, and so on.
In the example above, each tab only allows the user to proceed to the next step when the field isValid
receives a true
value.
If you want to perform more complicated logic tests to control how the user can proceed to the next step, you can define the logic in a separate function. Use the @submit
event to call that function.
Programmatic Navigation
The stepper provides methods to programmatically navigate between steps:
- Genesis
- React
- Angular
@customElement({
name: 'stepper-navigation-example',
template: html`
<rapid-stepper ref="stepper">
<rapid-stepper-tab>Step 1</rapid-stepper-tab>
<rapid-stepper-tab>Step 2</rapid-stepper-tab>
<rapid-stepper-tab>Step 3</rapid-stepper-tab>
<rapid-stepper-tab-panel>Content 1</rapid-stepper-tab-panel>
<rapid-stepper-tab-panel>Content 2</rapid-stepper-tab-panel>
<rapid-stepper-tab-panel>Content 3</rapid-stepper-tab-panel>
</rapid-stepper>
<rapid-button @click={\`\${(x) => x.goToFirst()}\`}>Go to First</rapid-button>
<rapid-button @click={\`\${(x) => x.goToLast()}\`}>Go to Last</rapid-button>
<rapid-button @click={\`\${(x) => x.goToSpecific()}\`}>Go to Step 2</rapid-button>
`,
})
export class StepperNavigationExample extends GenesisElement {
@observable stepper: any;
goToFirst() {
this.stepper.goToFirstStep();
}
goToLast() {
this.stepper.goToLastStep();
}
goToSpecific() {
this.stepper.goToStep(2);
}
}
import React, { useRef } from 'react';
export function StepperNavigationExample() {
const stepperRef = useRef(null);
const goToFirst = () => {
stepperRef.current?.goToFirstStep();
};
const goToLast = () => {
stepperRef.current?.goToLastStep();
};
const goToSpecific = () => {
stepperRef.current?.goToStep(2);
};
return (
<rapid-stepper ref={stepperRef}>
<rapid-stepper-tab>Step 1</rapid-stepper-tab>
<rapid-stepper-tab>Step 2</rapid-stepper-tab>
<rapid-stepper-tab>Step 3</rapid-stepper-tab>
<rapid-stepper-tab-panel>Content 1</rapid-stepper-tab-panel>
<rapid-stepper-tab-panel>Content 2</rapid-stepper-tab-panel>
<rapid-stepper-tab-panel>Content 3</rapid-stepper-tab-panel>
</rapid-stepper>
<rapid-button onClick={goToFirst}>Go to First</rapid-button>
<rapid-button onClick={goToLast}>Go to Last</rapid-button>
<rapid-button onClick={goToSpecific}>Go to Step 2</rapid-button>
);
}
import { Component, ViewChild, ElementRef } from '@angular/core';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
@Component({
selector: 'stepper-navigation-example',
template: `
<rapid-stepper #stepper>
<rapid-stepper-tab>Step 1</rapid-stepper-tab>
<rapid-stepper-tab>Step 2</rapid-stepper-tab>
<rapid-stepper-tab>Step 3</rapid-stepper-tab>
<rapid-stepper-tab-panel>Content 1</rapid-stepper-tab-panel>
<rapid-stepper-tab-panel>Content 2</rapid-stepper-tab-panel>
<rapid-stepper-tab-panel>Content 3</rapid-stepper-tab-panel>
</rapid-stepper>
<rapid-button (click)="goToFirst()">Go to First</rapid-button>
<rapid-button (click)="goToLast()">Go to Last</rapid-button>
<rapid-button (click)="goToSpecific()">Go to Step 2</rapid-button>
`,
standalone: true,
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class StepperNavigationExampleComponent {
@ViewChild('stepper', { static: true }) stepper!: ElementRef;
goToFirst() {
this.stepper.nativeElement.goToFirstStep();
}
goToLast() {
this.stepper.nativeElement.goToLastStep();
}
goToSpecific() {
this.stepper.nativeElement.goToStep(2);
}
}
Button Visibility Control
You can control the visibility of stepper buttons using various attributes:
// Hide only the submit button
<rapid-stepper hide-submit-button>
<!-- stepper content -->
</rapid-stepper>
// Hide all navigation buttons
<rapid-stepper hide-all-buttons>
<!-- stepper content -->
</rapid-stepper>
// Hide step numbers in tabs
<rapid-stepper hide-step-number>
<!-- stepper content -->
</rapid-stepper>
Jump Navigation
Enable users to jump between steps by clicking on step tabs:
// Allow backward jumps (clicking on previous steps)
<rapid-stepper allow-backward-jumps>
<!-- stepper content -->
</rapid-stepper>
// Allow forward jumps (clicking on future steps with validation)
<rapid-stepper allow-forward-jumps>
<!-- stepper content -->
</rapid-stepper>
// Allow both directions
<rapid-stepper allow-backward-jumps allow-forward-jumps>
<!-- stepper content -->
</rapid-stepper>
When allow-forward-jumps
is enabled, the stepper will validate all intermediate steps before allowing the jump. If validation fails, a validation-failure
event is fired.