Skip to content

Commit cb9148d

Browse files
authored
fix(material/stepper): allow stepper to be labelled (#33137)
Fixes that users didn't have a way to label the stepper after we changed the internal roles. Fixes #33130.
1 parent a2392bf commit cb9148d

4 files changed

Lines changed: 40 additions & 8 deletions

File tree

goldens/material/stepper/index.api.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ export class MatStepper extends CdkStepper implements AfterViewInit, AfterConten
113113
readonly animationDone: EventEmitter<void>;
114114
get animationDuration(): string;
115115
set animationDuration(value: string);
116+
ariaLabel: string | null;
116117
color: ThemePalette;
117118
disableRipple: boolean;
118119
// (undocumented)
@@ -135,7 +136,7 @@ export class MatStepper extends CdkStepper implements AfterViewInit, AfterConten
135136
readonly steps: QueryList<MatStep>;
136137
_steps: QueryList<MatStep>;
137138
// (undocumented)
138-
static ɵcmp: i0.ɵɵComponentDeclaration<MatStepper, "mat-stepper, mat-vertical-stepper, mat-horizontal-stepper, [matStepper]", ["matStepper", "matVerticalStepper", "matHorizontalStepper"], { "disableRipple": { "alias": "disableRipple"; "required": false; }; "color": { "alias": "color"; "required": false; }; "labelPosition": { "alias": "labelPosition"; "required": false; }; "headerPosition": { "alias": "headerPosition"; "required": false; }; "headerPrefix": { "alias": "headerPrefix"; "required": false; "isSignal": true; }; "animationDuration": { "alias": "animationDuration"; "required": false; }; }, { "animationDone": "animationDone"; }, ["_steps", "_icons"], ["*"], true, never>;
139+
static ɵcmp: i0.ɵɵComponentDeclaration<MatStepper, "mat-stepper, mat-vertical-stepper, mat-horizontal-stepper, [matStepper]", ["matStepper", "matVerticalStepper", "matHorizontalStepper"], { "disableRipple": { "alias": "disableRipple"; "required": false; }; "color": { "alias": "color"; "required": false; }; "labelPosition": { "alias": "labelPosition"; "required": false; }; "headerPosition": { "alias": "headerPosition"; "required": false; }; "ariaLabel": { "alias": "aria-label"; "required": false; }; "headerPrefix": { "alias": "headerPrefix"; "required": false; "isSignal": true; }; "animationDuration": { "alias": "animationDuration"; "required": false; }; }, { "animationDone": "animationDone"; }, ["_steps", "_icons"], ["*"], true, never>;
139140
// (undocumented)
140141
static ɵfac: i0.ɵɵFactoryDeclaration<MatStepper, never>;
141142
}

src/material/stepper/stepper.html

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,9 @@
5555
class="mat-vertical-content-container"
5656
[class.mat-stepper-vertical-line]="!$last"
5757
[class.mat-vertical-content-container-active]="selectedIndex === $index"
58-
[attr.inert]="selectedIndex === $index ? null : ''">
59-
<div
58+
[attr.inert]="selectedIndex === $index ? null : ''"
59+
[attr.aria-label]="ariaLabel">
60+
<div
6061
class="mat-vertical-stepper-content"
6162
role="region"
6263
[id]="_getStepContentId($index)"
@@ -105,10 +106,11 @@
105106
</ng-template>
106107

107108
<ng-template #horizontalStepsTemplate let-steps="steps">
108-
<div
109+
<div
109110
aria-orientation="horizontal"
110-
class="mat-horizontal-stepper-header-container"
111-
role="tablist">
111+
class="mat-horizontal-stepper-header-container"
112+
role="tablist"
113+
[attr.aria-label]="ariaLabel">
112114
@for (step of steps; track step) {
113115
<ng-container
114116
[ngTemplateOutlet]="stepTemplate"

src/material/stepper/stepper.spec.ts

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1017,6 +1017,15 @@ describe('MatStepper', () => {
10171017
expect(headers[2].classList.contains('mat-primary')).toBe(true);
10181018
expect(headers[1].classList.contains('mat-accent')).toBe(true);
10191019
});
1020+
1021+
it('should set an aria label on the content container', () => {
1022+
const fixture = createComponent(SimpleMatVerticalStepperApp);
1023+
fixture.componentInstance.ariaLabel.set('My Stepper');
1024+
fixture.detectChanges();
1025+
1026+
const container = fixture.nativeElement.querySelector('.mat-vertical-content-container');
1027+
expect(container.getAttribute('aria-label')).toBe('My Stepper');
1028+
});
10201029
});
10211030

10221031
describe('horizontal stepper', () => {
@@ -1217,6 +1226,17 @@ describe('MatStepper', () => {
12171226

12181227
expect(stepperHost.classList).toContain('mat-stepper-header-position-bottom');
12191228
});
1229+
1230+
it('should set an aria-label on the header container', () => {
1231+
const fixture = createComponent(SimpleMatHorizontalStepperApp);
1232+
fixture.componentInstance.ariaLabel.set('My Stepper');
1233+
fixture.detectChanges();
1234+
1235+
const container = fixture.nativeElement.querySelector(
1236+
'.mat-horizontal-stepper-header-container',
1237+
);
1238+
expect(container.getAttribute('aria-label')).toBe('My Stepper');
1239+
});
12201240
});
12211241

12221242
describe('linear stepper with valid step', () => {
@@ -1849,7 +1869,8 @@ class MatHorizontalStepperWithErrorsApp {
18491869
<mat-stepper
18501870
[disableRipple]="disableRipple()"
18511871
[color]="stepperTheme()"
1852-
[headerPosition]="headerPosition()">
1872+
[headerPosition]="headerPosition()"
1873+
[aria-label]="ariaLabel()">
18531874
<mat-step>
18541875
<ng-template matStepLabel>Step 1</ng-template>
18551876
Content 1
@@ -1881,6 +1902,7 @@ class MatHorizontalStepperWithErrorsApp {
18811902
class SimpleMatHorizontalStepperApp {
18821903
@ViewChild(MatStepper) stepper!: MatStepper;
18831904
inputLabel = 'Step 3';
1905+
ariaLabel = signal<string | null>(null);
18841906
disableRipple = signal(false);
18851907
stepperTheme = signal<ThemePalette>(undefined);
18861908
secondStepTheme = signal<ThemePalette>(undefined);
@@ -1889,7 +1911,7 @@ class SimpleMatHorizontalStepperApp {
18891911

18901912
@Component({
18911913
template: `
1892-
<mat-stepper orientation="vertical" [disableRipple]="disableRipple()" [color]="stepperTheme()">
1914+
<mat-stepper orientation="vertical" [disableRipple]="disableRipple()" [color]="stepperTheme()" [aria-label]="ariaLabel()">
18931915
<mat-step>
18941916
<ng-template matStepLabel>Step 1</ng-template>
18951917
Content 1
@@ -1923,6 +1945,7 @@ class SimpleMatHorizontalStepperApp {
19231945
class SimpleMatVerticalStepperApp {
19241946
@ViewChild(MatStepper) stepper!: MatStepper;
19251947
inputLabel = signal('Step 3');
1948+
ariaLabel = signal<string | null>(null);
19261949
showStepTwo = signal(true);
19271950
disableRipple = signal(false);
19281951
stepperTheme = signal<ThemePalette>(undefined);

src/material/stepper/stepper.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,12 @@ export class MatStepper extends CdkStepper implements AfterViewInit, AfterConten
188188
@Input()
189189
headerPosition: 'top' | 'bottom' = 'top';
190190

191+
/**
192+
* ARIA label for the stepper.
193+
*/
194+
@Input('aria-label')
195+
ariaLabel: string | null = null;
196+
191197
/** The content prefix to use in the stepper header. */
192198
readonly headerPrefix = input<TemplateRef<unknown> | null>(null);
193199

0 commit comments

Comments
 (0)