Skip to content

Commit 0e8c4f9

Browse files
committed
fix(material/stepper): updates vertical-stepper aria roles
Updates Angular Component's vertical stepper to use more generic aria roles since having the default tablist/tab/tabpanel applied to the vertical stepper violates WCAG rules of having tabpanel as a nested child within tablist. The new roles of group and region satisfy aria requirements while maintaining the current html structure of the vertical stepper. Fixes b/361783174
1 parent db090ca commit 0e8c4f9

File tree

4 files changed

+29
-30
lines changed

4 files changed

+29
-30
lines changed

src/cdk/stepper/step-header.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,6 @@ import {FocusableOption} from '@angular/cdk/a11y';
1111

1212
@Directive({
1313
selector: '[cdkStepHeader]',
14-
host: {
15-
'role': 'tab',
16-
},
1714
})
1815
export class CdkStepHeader implements FocusableOption {
1916
_elementRef = inject<ElementRef<HTMLElement>>(ElementRef);

src/material/stepper/step-header.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ import {_CdkPrivateStyleLoader, _VisuallyHiddenLoader} from '@angular/cdk/privat
3535
host: {
3636
'class': 'mat-step-header',
3737
'[class]': '"mat-" + (color || "primary")',
38-
'role': 'tab',
3938
},
4039
encapsulation: ViewEncapsulation.None,
4140
changeDetection: ChangeDetectionStrategy.OnPush,

src/material/stepper/stepper.html

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
@switch (orientation) {
1212
@case ('horizontal') {
1313
<div class="mat-horizontal-stepper-wrapper">
14-
<div class="mat-horizontal-stepper-header-container">
14+
<div class="mat-horizontal-stepper-header-container" role="tablist">
1515
@for (step of steps; track step) {
1616
<ng-container
1717
[ngTemplateOutlet]="stepTemplate"
@@ -40,28 +40,30 @@
4040
}
4141

4242
@case ('vertical') {
43-
@for (step of steps; track step) {
44-
<div class="mat-step">
45-
<ng-container
46-
[ngTemplateOutlet]="stepTemplate"
47-
[ngTemplateOutletContext]="{step, i: $index}"/>
48-
<div
49-
#animatedContainer
50-
class="mat-vertical-content-container"
51-
[class.mat-stepper-vertical-line]="!$last"
52-
[class.mat-vertical-content-container-active]="selectedIndex === $index"
53-
[attr.inert]="selectedIndex === $index ? null : ''">
54-
<div class="mat-vertical-stepper-content"
55-
role="tabpanel"
56-
[id]="_getStepContentId($index)"
57-
[attr.aria-labelledby]="_getStepLabelId($index)">
58-
<div class="mat-vertical-content">
59-
<ng-container [ngTemplateOutlet]="step.content"/>
43+
<div class="mat-vertical-stepper-wrapper" role="group">
44+
@for (step of steps; track step) {
45+
<div class="mat-step" role="group">
46+
<ng-container
47+
[ngTemplateOutlet]="stepTemplate"
48+
[ngTemplateOutletContext]="{step, i: $index}"/>
49+
<div
50+
#animatedContainer
51+
class="mat-vertical-content-container"
52+
[class.mat-stepper-vertical-line]="!$last"
53+
[class.mat-vertical-content-container-active]="selectedIndex === $index"
54+
[attr.inert]="selectedIndex === $index ? null : ''">
55+
<div class="mat-vertical-stepper-content"
56+
role="region"
57+
[id]="_getStepContentId($index)"
58+
[attr.aria-labelledby]="_getStepLabelId($index)">
59+
<div class="mat-vertical-content">
60+
<ng-container [ngTemplateOutlet]="step.content"/>
61+
</div>
6062
</div>
6163
</div>
6264
</div>
63-
</div>
64-
}
65+
}
66+
</div>
6567
}
6668
}
6769

@@ -70,15 +72,17 @@
7072
<mat-step-header
7173
[class.mat-horizontal-stepper-header]="orientation === 'horizontal'"
7274
[class.mat-vertical-stepper-header]="orientation === 'vertical'"
75+
[attr.role]="orientation === 'horizontal' ? 'tab' : 'button'"
7376
(click)="step.select()"
7477
(keydown)="_onKeydown($event)"
7578
[tabIndex]="_getFocusIndex() === i ? 0 : -1"
7679
[id]="_getStepLabelId(i)"
77-
[attr.aria-posinset]="i + 1"
78-
[attr.aria-setsize]="steps.length"
79-
[attr.aria-controls]="_getStepContentId(i)"
80-
[attr.aria-selected]="selectedIndex == i"
81-
[attr.aria-label]="step.ariaLabel || null"
80+
[attr.aria-posinset]="orientation === 'horizontal' ? i + 1 : undefined"
81+
[attr.aria-setsize]="orientation === 'horizontal' ? steps.length : undefined"
82+
[attr.aria-controls]="orientation === 'horizontal' ? _getStepContentId(i) : undefined"
83+
[attr.aria-selected]="orientation === 'horizontal' ? selectedIndex == i : undefined"
84+
[attr.aria-current]="orientation === 'vertical' ? selectedIndex == i : undefined"
85+
[attr.aria-label]="step.ariaLabel || `Step ${i+1}`"
8286
[attr.aria-labelledby]="(!step.ariaLabel && step.ariaLabelledby) ? step.ariaLabelledby : null"
8387
[attr.aria-disabled]="_stepIsNavigable(i, step) ? null : true"
8488
[index]="i"

src/material/stepper/stepper.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,6 @@ export class MatStep extends CdkStep implements ErrorStateMatcher, AfterContentI
132132
'[class.mat-stepper-animating]': '_isAnimating()',
133133
'[style.--mat-stepper-animation-duration]': '_getAnimationDuration()',
134134
'[attr.aria-orientation]': 'orientation',
135-
'role': 'tablist',
136135
},
137136
providers: [{provide: CdkStepper, useExisting: MatStepper}],
138137
encapsulation: ViewEncapsulation.None,

0 commit comments

Comments
 (0)