Skip to content

Commit e1d85d2

Browse files
authored
fix(checkbox): pass aria-describedby through to input (#19495)
Passes the `aria-describedby` attribute value through to the underlying `input` element. Fixes #19477.
1 parent 31afc80 commit e1d85d2

File tree

7 files changed

+74
-1
lines changed

7 files changed

+74
-1
lines changed

src/material-experimental/mdc-checkbox/checkbox.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
[attr.aria-checked]="_getAriaChecked()"
88
[attr.aria-label]="ariaLabel || null"
99
[attr.aria-labelledby]="ariaLabelledby"
10+
[attr.aria-describedby]="ariaDescribedby"
1011
[attr.name]="name"
1112
[attr.value]="value"
1213
[checked]="checked"

src/material-experimental/mdc-checkbox/checkbox.spec.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,32 @@ describe('MDC-based MatCheckbox', () => {
702702
}));
703703
});
704704

705+
describe('with provided aria-describedby ', () => {
706+
let checkboxDebugElement: DebugElement;
707+
let checkboxNativeElement: HTMLElement;
708+
let inputElement: HTMLInputElement;
709+
710+
it('should use the provided aria-describedby', () => {
711+
fixture = createComponent(CheckboxWithAriaDescribedby);
712+
checkboxDebugElement = fixture.debugElement.query(By.directive(MatCheckbox))!;
713+
checkboxNativeElement = checkboxDebugElement.nativeElement;
714+
inputElement = <HTMLInputElement>checkboxNativeElement.querySelector('input');
715+
716+
fixture.detectChanges();
717+
expect(inputElement.getAttribute('aria-describedby')).toBe('some-id');
718+
});
719+
720+
it('should not assign aria-describedby if none is provided', () => {
721+
fixture = createComponent(SingleCheckbox);
722+
checkboxDebugElement = fixture.debugElement.query(By.directive(MatCheckbox))!;
723+
checkboxNativeElement = checkboxDebugElement.nativeElement;
724+
inputElement = <HTMLInputElement>checkboxNativeElement.querySelector('input');
725+
726+
fixture.detectChanges();
727+
expect(inputElement.getAttribute('aria-describedby')).toBe(null);
728+
});
729+
});
730+
705731
describe('with provided tabIndex', () => {
706732
let checkboxDebugElement: DebugElement;
707733
let checkboxNativeElement: HTMLElement;
@@ -1111,6 +1137,12 @@ class CheckboxWithAriaLabel {
11111137
class CheckboxWithAriaLabelledby {
11121138
}
11131139

1140+
/** Simple test component with an aria-describedby set. */
1141+
@Component({
1142+
template: `<mat-checkbox aria-describedby="some-id"></mat-checkbox>`
1143+
})
1144+
class CheckboxWithAriaDescribedby {}
1145+
11141146
/** Simple test component with name attribute */
11151147
@Component({template: `<mat-checkbox name="test-name"></mat-checkbox>`})
11161148
class CheckboxWithNameAttribute {

src/material-experimental/mdc-checkbox/checkbox.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@ export class MatCheckbox implements AfterViewInit, OnDestroy, ControlValueAccess
8686
/** The `aria-labelledby` attribute to use for the input element. */
8787
@Input('aria-labelledby') ariaLabelledby: string|null = null;
8888

89+
/** The 'aria-describedby' attribute is read after the element's label and field type. */
90+
@Input('aria-describedby') ariaDescribedby: string;
91+
8992
/** The color palette for this checkbox ('primary', 'accent', or 'warn'). */
9093
@Input() color: ThemePalette = 'accent';
9194

src/material/checkbox/checkbox.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
[attr.aria-label]="ariaLabel || null"
1414
[attr.aria-labelledby]="ariaLabelledby"
1515
[attr.aria-checked]="_getAriaChecked()"
16+
[attr.aria-describedby]="ariaDescribedby"
1617
(change)="_onInteractionEvent($event)"
1718
(click)="_onInputClick($event)">
1819
<div matRipple class="mat-checkbox-ripple mat-focus-indicator"

src/material/checkbox/checkbox.spec.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -784,6 +784,32 @@ describe('MatCheckbox', () => {
784784
});
785785
});
786786

787+
describe('with provided aria-describedby ', () => {
788+
let checkboxDebugElement: DebugElement;
789+
let checkboxNativeElement: HTMLElement;
790+
let inputElement: HTMLInputElement;
791+
792+
it('should use the provided aria-describedby', () => {
793+
fixture = createComponent(CheckboxWithAriaDescribedby);
794+
checkboxDebugElement = fixture.debugElement.query(By.directive(MatCheckbox))!;
795+
checkboxNativeElement = checkboxDebugElement.nativeElement;
796+
inputElement = <HTMLInputElement>checkboxNativeElement.querySelector('input');
797+
798+
fixture.detectChanges();
799+
expect(inputElement.getAttribute('aria-describedby')).toBe('some-id');
800+
});
801+
802+
it('should not assign aria-describedby if none is provided', () => {
803+
fixture = createComponent(SingleCheckbox);
804+
checkboxDebugElement = fixture.debugElement.query(By.directive(MatCheckbox))!;
805+
checkboxNativeElement = checkboxDebugElement.nativeElement;
806+
inputElement = <HTMLInputElement>checkboxNativeElement.querySelector('input');
807+
808+
fixture.detectChanges();
809+
expect(inputElement.getAttribute('aria-describedby')).toBe(null);
810+
});
811+
});
812+
787813
describe('with provided tabIndex', () => {
788814
let checkboxDebugElement: DebugElement;
789815
let checkboxNativeElement: HTMLElement;
@@ -1346,6 +1372,12 @@ class CheckboxWithAriaLabel { }
13461372
})
13471373
class CheckboxWithAriaLabelledby {}
13481374

1375+
/** Simple test component with an aria-describedby set. */
1376+
@Component({
1377+
template: `<mat-checkbox aria-describedby="some-id"></mat-checkbox>`
1378+
})
1379+
class CheckboxWithAriaDescribedby {}
1380+
13491381
/** Simple test component with name attribute */
13501382
@Component({
13511383
template: `<mat-checkbox name="test-name"></mat-checkbox>`

src/material/checkbox/checkbox.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,9 @@ export class MatCheckbox extends _MatCheckboxMixinBase implements ControlValueAc
146146
*/
147147
@Input('aria-labelledby') ariaLabelledby: string | null = null;
148148

149+
/** The 'aria-describedby' attribute is read after the element's label and field type. */
150+
@Input('aria-describedby') ariaDescribedby: string;
151+
149152
private _uniqueId: string = `mat-checkbox-${++nextUniqueId}`;
150153

151154
/** A unique id for the checkbox input. If none is supplied, it will be auto-generated. */

tools/public_api_guard/material/checkbox.d.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export declare class MatCheckbox extends _MatCheckboxMixinBase implements Contro
1717
_animationMode?: string | undefined;
1818
_inputElement: ElementRef<HTMLInputElement>;
1919
_onTouched: () => any;
20+
ariaDescribedby: string;
2021
ariaLabel: string;
2122
ariaLabelledby: string | null;
2223
readonly change: EventEmitter<MatCheckboxChange>;
@@ -55,7 +56,7 @@ export declare class MatCheckbox extends _MatCheckboxMixinBase implements Contro
5556
static ngAcceptInputType_disabled: BooleanInput;
5657
static ngAcceptInputType_indeterminate: BooleanInput;
5758
static ngAcceptInputType_required: BooleanInput;
58-
static ɵcmp: i0.ɵɵComponentDefWithMeta<MatCheckbox, "mat-checkbox", ["matCheckbox"], { "disableRipple": "disableRipple"; "color": "color"; "tabIndex": "tabIndex"; "ariaLabel": "aria-label"; "ariaLabelledby": "aria-labelledby"; "id": "id"; "required": "required"; "labelPosition": "labelPosition"; "name": "name"; "value": "value"; "checked": "checked"; "disabled": "disabled"; "indeterminate": "indeterminate"; }, { "change": "change"; "indeterminateChange": "indeterminateChange"; }, never, ["*"]>;
59+
static ɵcmp: i0.ɵɵComponentDefWithMeta<MatCheckbox, "mat-checkbox", ["matCheckbox"], { "disableRipple": "disableRipple"; "color": "color"; "tabIndex": "tabIndex"; "ariaLabel": "aria-label"; "ariaLabelledby": "aria-labelledby"; "ariaDescribedby": "aria-describedby"; "id": "id"; "required": "required"; "labelPosition": "labelPosition"; "name": "name"; "value": "value"; "checked": "checked"; "disabled": "disabled"; "indeterminate": "indeterminate"; }, { "change": "change"; "indeterminateChange": "indeterminateChange"; }, never, ["*"]>;
5960
static ɵfac: i0.ɵɵFactoryDef<MatCheckbox, [null, null, null, null, { attribute: "tabindex"; }, { optional: true; }, { optional: true; }, { optional: true; }]>;
6061
}
6162

0 commit comments

Comments
 (0)