mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
fix(stepper): unable to set aria-label on step (#11989)
Along the same lines as #11898. In our stepper docs we recommend for people to add a meaningful label via `aria-label` or `aria-labelledby`, however even if they do, the attributes don't get forwarded to the underlying element that has the proper role. These changes add inputs for `aria-label` and `aria-labelledby` and correctly forward the attributes.
This commit is contained in:
committed by
Jeremy Elbourn
parent
3bf10f9aed
commit
ae39535644
@@ -84,9 +84,18 @@ export class CdkStep implements OnChanges {
|
||||
/** Whether user has seen the expanded step content or not. */
|
||||
interacted = false;
|
||||
|
||||
/** Label of the step. */
|
||||
/** Plain text label of the step. */
|
||||
@Input() label: string;
|
||||
|
||||
/** Aria label for the tab. */
|
||||
@Input('aria-label') ariaLabel: string;
|
||||
|
||||
/**
|
||||
* Reference to the element that the tab is labelled by.
|
||||
* Will be cleared if `aria-label` is set at the same time.
|
||||
*/
|
||||
@Input('aria-labelledby') ariaLabelledby: string;
|
||||
|
||||
/** Whether the user can return to this step once it has been marked as complted. */
|
||||
@Input()
|
||||
get editable(): boolean { return this._editable; }
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
[attr.aria-setsize]="_steps.length"
|
||||
[attr.aria-controls]="_getStepContentId(i)"
|
||||
[attr.aria-selected]="selectedIndex == i"
|
||||
[attr.aria-label]="step.ariaLabel || null"
|
||||
[attr.aria-labelledby]="(!step.ariaLabel && step.ariaLabelledby) ? step.ariaLabelledby : null"
|
||||
[index]="i"
|
||||
[state]="_getIndicatorType(i)"
|
||||
[label]="step.stepLabel || step.label"
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
[attr.aria-setsize]="_steps.length"
|
||||
[attr.aria-controls]="_getStepContentId(i)"
|
||||
[attr.aria-selected]="selectedIndex === i"
|
||||
[attr.aria-label]="step.ariaLabel || null"
|
||||
[attr.aria-labelledby]="(!step.ariaLabel && step.ariaLabelledby) ? step.ariaLabelledby : null"
|
||||
[index]="i"
|
||||
[state]="_getIndicatorType(i)"
|
||||
[label]="step.stepLabel || step.label"
|
||||
|
||||
@@ -54,6 +54,7 @@ describe('MatStepper', () => {
|
||||
SimpleStepperWithStepControlAndCompletedBinding,
|
||||
SimpleMatHorizontalStepperApp,
|
||||
LinearStepperWithValidOptionalStep,
|
||||
StepperWithAriaInputs,
|
||||
],
|
||||
providers: [
|
||||
{provide: Directionality, useFactory: () => dir}
|
||||
@@ -836,6 +837,46 @@ describe('MatStepper', () => {
|
||||
expect(stepper.selectedIndex).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('aria labelling', () => {
|
||||
let fixture: ComponentFixture<StepperWithAriaInputs>;
|
||||
let stepHeader: HTMLElement;
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(StepperWithAriaInputs);
|
||||
fixture.detectChanges();
|
||||
stepHeader = fixture.nativeElement.querySelector('.mat-step-header');
|
||||
});
|
||||
|
||||
it('should not set aria-label or aria-labelledby attributes if they are not passed in', () => {
|
||||
expect(stepHeader.hasAttribute('aria-label')).toBe(false);
|
||||
expect(stepHeader.hasAttribute('aria-labelledby')).toBe(false);
|
||||
});
|
||||
|
||||
it('should set the aria-label attribute', () => {
|
||||
fixture.componentInstance.ariaLabel = 'First step';
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(stepHeader.getAttribute('aria-label')).toBe('First step');
|
||||
});
|
||||
|
||||
it('should set the aria-labelledby attribute', () => {
|
||||
fixture.componentInstance.ariaLabelledby = 'first-step-label';
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(stepHeader.getAttribute('aria-labelledby')).toBe('first-step-label');
|
||||
});
|
||||
|
||||
it('should not be able to set both an aria-label and aria-labelledby', () => {
|
||||
fixture.componentInstance.ariaLabel = 'First step';
|
||||
fixture.componentInstance.ariaLabelledby = 'first-step-label';
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(stepHeader.getAttribute('aria-label')).toBe('First step');
|
||||
expect(stepHeader.hasAttribute('aria-labelledby')).toBe(false);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
/** Asserts that keyboard interaction works correctly. */
|
||||
@@ -1158,3 +1199,16 @@ class LinearStepperWithValidOptionalStep {
|
||||
controls = [0, 0, 0].map(() => new FormControl());
|
||||
step2Optional = false;
|
||||
}
|
||||
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<mat-horizontal-stepper>
|
||||
<mat-step [aria-label]="ariaLabel" [aria-labelledby]="ariaLabelledby" label="One"></mat-step>
|
||||
</mat-horizontal-stepper>
|
||||
`
|
||||
})
|
||||
class StepperWithAriaInputs {
|
||||
ariaLabel: string;
|
||||
ariaLabelledby: string;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user