Skip to content

Commit 51271c6

Browse files
committed
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. (cherry picked from commit cb9148d)
1 parent 43b5e11 commit 51271c6

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
@@ -114,6 +114,7 @@ export class MatStepper extends CdkStepper implements AfterViewInit, AfterConten
114114
readonly animationDone: EventEmitter<void>;
115115
get animationDuration(): string;
116116
set animationDuration(value: string);
117+
ariaLabel: string | null;
117118
color: ThemePalette;
118119
disableRipple: boolean;
119120
// (undocumented)
@@ -136,7 +137,7 @@ export class MatStepper extends CdkStepper implements AfterViewInit, AfterConten
136137
readonly steps: QueryList<MatStep>;
137138
_steps: QueryList<MatStep>;
138139
// (undocumented)
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; }; "headerPrefix": { "alias": "headerPrefix"; "required": false; "isSignal": true; }; "animationDuration": { "alias": "animationDuration"; "required": false; }; }, { "animationDone": "animationDone"; }, ["_steps", "_icons"], ["*"], true, never>;
140+
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>;
140141
// (undocumented)
141142
static ɵfac: i0.ɵɵFactoryDeclaration<MatStepper, never>;
142143
}

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
@@ -1014,6 +1014,15 @@ describe('MatStepper', () => {
10141014
expect(headers[2].classList.contains('mat-primary')).toBe(true);
10151015
expect(headers[1].classList.contains('mat-accent')).toBe(true);
10161016
});
1017+
1018+
it('should set an aria label on the content container', () => {
1019+
const fixture = createComponent(SimpleMatVerticalStepperApp);
1020+
fixture.componentInstance.ariaLabel.set('My Stepper');
1021+
fixture.detectChanges();
1022+
1023+
const container = fixture.nativeElement.querySelector('.mat-vertical-content-container');
1024+
expect(container.getAttribute('aria-label')).toBe('My Stepper');
1025+
});
10171026
});
10181027

10191028
describe('horizontal stepper', () => {
@@ -1214,6 +1223,17 @@ describe('MatStepper', () => {
12141223

12151224
expect(stepperHost.classList).toContain('mat-stepper-header-position-bottom');
12161225
});
1226+
1227+
it('should set an aria-label on the header container', () => {
1228+
const fixture = createComponent(SimpleMatHorizontalStepperApp);
1229+
fixture.componentInstance.ariaLabel.set('My Stepper');
1230+
fixture.detectChanges();
1231+
1232+
const container = fixture.nativeElement.querySelector(
1233+
'.mat-horizontal-stepper-header-container',
1234+
);
1235+
expect(container.getAttribute('aria-label')).toBe('My Stepper');
1236+
});
12171237
});
12181238

12191239
describe('linear stepper with valid step', () => {
@@ -1845,7 +1865,8 @@ class MatHorizontalStepperWithErrorsApp {
18451865
<mat-stepper
18461866
[disableRipple]="disableRipple()"
18471867
[color]="stepperTheme()"
1848-
[headerPosition]="headerPosition()">
1868+
[headerPosition]="headerPosition()"
1869+
[aria-label]="ariaLabel()">
18491870
<mat-step>
18501871
<ng-template matStepLabel>Step 1</ng-template>
18511872
Content 1
@@ -1876,6 +1897,7 @@ class MatHorizontalStepperWithErrorsApp {
18761897
class SimpleMatHorizontalStepperApp {
18771898
@ViewChild(MatStepper) stepper!: MatStepper;
18781899
inputLabel = 'Step 3';
1900+
ariaLabel = signal<string | null>(null);
18791901
disableRipple = signal(false);
18801902
stepperTheme = signal<ThemePalette>(undefined);
18811903
secondStepTheme = signal<ThemePalette>(undefined);
@@ -1884,7 +1906,7 @@ class SimpleMatHorizontalStepperApp {
18841906

18851907
@Component({
18861908
template: `
1887-
<mat-stepper orientation="vertical" [disableRipple]="disableRipple()" [color]="stepperTheme()">
1909+
<mat-stepper orientation="vertical" [disableRipple]="disableRipple()" [color]="stepperTheme()" [aria-label]="ariaLabel()">
18881910
<mat-step>
18891911
<ng-template matStepLabel>Step 1</ng-template>
18901912
Content 1
@@ -1917,6 +1939,7 @@ class SimpleMatHorizontalStepperApp {
19171939
class SimpleMatVerticalStepperApp {
19181940
@ViewChild(MatStepper) stepper!: MatStepper;
19191941
inputLabel = signal('Step 3');
1942+
ariaLabel = signal<string | null>(null);
19201943
showStepTwo = signal(true);
19211944
disableRipple = signal(false);
19221945
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)