From efbc13b83eebeaeee0f6d3cb1f5bf09bbcd84fee Mon Sep 17 00:00:00 2001 From: Joy Serquina Date: Tue, 7 Jan 2025 22:54:55 +0000 Subject: [PATCH 1/5] fix(material/timepicker): adds aria-labelledby to timepicker toggle Updates Angular Component Timepicker so the timepicker toggle uses the aria-labelledby value for the timepicker toggle button to make it more accessible. Fixes b/380308482 --- src/dev-app/timepicker/timepicker-demo.html | 2 +- src/material/timepicker/timepicker-toggle.html | 1 + src/material/timepicker/timepicker-toggle.ts | 5 +++++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/dev-app/timepicker/timepicker-demo.html b/src/dev-app/timepicker/timepicker-demo.html index 52abf423e2d6..8d4883c161eb 100644 --- a/src/dev-app/timepicker/timepicker-demo.html +++ b/src/dev-app/timepicker/timepicker-demo.html @@ -11,7 +11,7 @@

Basic timepicker

[matTimepickerMax]="maxControl.value" [formControl]="control"> - +

Value: {{control.value}}

diff --git a/src/material/timepicker/timepicker-toggle.html b/src/material/timepicker/timepicker-toggle.html index ef15001b8e5a..59b02ad09ad3 100644 --- a/src/material/timepicker/timepicker-toggle.html +++ b/src/material/timepicker/timepicker-toggle.html @@ -3,6 +3,7 @@ type="button" aria-haspopup="listbox" [attr.aria-label]="ariaLabel()" + [attr.aria-labelledby]="ariaLabelledby()" [attr.aria-expanded]="timepicker().isOpen()" [attr.tabindex]="_isDisabled() ? -1 : tabIndex()" [disabled]="_isDisabled()" diff --git a/src/material/timepicker/timepicker-toggle.ts b/src/material/timepicker/timepicker-toggle.ts index 9bf902390a16..d28f62399be5 100644 --- a/src/material/timepicker/timepicker-toggle.ts +++ b/src/material/timepicker/timepicker-toggle.ts @@ -62,6 +62,11 @@ export class MatTimepickerToggle { alias: 'aria-label', }); + /** Screen-reader labelled by id for the button. */ + readonly ariaLabelledby = input(undefined, { + alias: 'aria-labelledby', + }); + /** Whether the toggle button is disabled. */ readonly disabled: InputSignalWithTransform = input(false, { transform: booleanAttribute, From e9050ebdc00ac422fd846606262262680552e6b5 Mon Sep 17 00:00:00 2001 From: Joy Serquina Date: Wed, 8 Jan 2025 21:16:11 +0000 Subject: [PATCH 2/5] fix(material/timepicker): adds default timepicker toggle aria-label Updates Angular Components Timepicker component by creating a default aria-label to the timepicker toggle if one is not supplied. This makes the button more accessible and descriptive for screen readers. Fix b/380308482 --- src/dev-app/timepicker/timepicker-demo.html | 2 +- src/material/timepicker/timepicker-toggle.html | 2 +- src/material/timepicker/timepicker-toggle.ts | 12 ++++++++++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/dev-app/timepicker/timepicker-demo.html b/src/dev-app/timepicker/timepicker-demo.html index 8d4883c161eb..52abf423e2d6 100644 --- a/src/dev-app/timepicker/timepicker-demo.html +++ b/src/dev-app/timepicker/timepicker-demo.html @@ -11,7 +11,7 @@

Basic timepicker

[matTimepickerMax]="maxControl.value" [formControl]="control"> - +

Value: {{control.value}}

diff --git a/src/material/timepicker/timepicker-toggle.html b/src/material/timepicker/timepicker-toggle.html index 59b02ad09ad3..879329c90dff 100644 --- a/src/material/timepicker/timepicker-toggle.html +++ b/src/material/timepicker/timepicker-toggle.html @@ -2,7 +2,7 @@ mat-icon-button type="button" aria-haspopup="listbox" - [attr.aria-label]="ariaLabel()" + [attr.aria-label]="getAriaLabel()" [attr.aria-labelledby]="ariaLabelledby()" [attr.aria-expanded]="timepicker().isOpen()" [attr.tabindex]="_isDisabled() ? -1 : tabIndex()" diff --git a/src/material/timepicker/timepicker-toggle.ts b/src/material/timepicker/timepicker-toggle.ts index d28f62399be5..b0e54ee77ca8 100644 --- a/src/material/timepicker/timepicker-toggle.ts +++ b/src/material/timepicker/timepicker-toggle.ts @@ -67,6 +67,9 @@ export class MatTimepickerToggle { alias: 'aria-labelledby', }); + /** Default aria-label for the toggle if none is provided. */ + private readonly defaultAriaLabel = 'Open timepicker options'; + /** Whether the toggle button is disabled. */ readonly disabled: InputSignalWithTransform = input(false, { transform: booleanAttribute, @@ -89,4 +92,13 @@ export class MatTimepickerToggle { event.stopPropagation(); } } + + /** + * Gets the aria-label to use for the toggle button. + * Returns the user-provided aria-label if one exists, + * otherwise returns the default aria-label using the timepicker's panelId. + */ + getAriaLabel(): string { + return this.ariaLabel() || this.defaultAriaLabel; + } } From 637a6baf339e6256e7adfc17705a356aa238f0ff Mon Sep 17 00:00:00 2001 From: Joy Serquina Date: Wed, 8 Jan 2025 23:11:41 +0000 Subject: [PATCH 3/5] refactor(material/timepicker): fix lint error Updates previous fix to fix lint error. --- src/material/timepicker/timepicker-toggle.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/material/timepicker/timepicker-toggle.ts b/src/material/timepicker/timepicker-toggle.ts index b0e54ee77ca8..193959bb841c 100644 --- a/src/material/timepicker/timepicker-toggle.ts +++ b/src/material/timepicker/timepicker-toggle.ts @@ -68,7 +68,7 @@ export class MatTimepickerToggle { }); /** Default aria-label for the toggle if none is provided. */ - private readonly defaultAriaLabel = 'Open timepicker options'; + private readonly _defaultAriaLabel = 'Open timepicker options'; /** Whether the toggle button is disabled. */ readonly disabled: InputSignalWithTransform = input(false, { @@ -99,6 +99,6 @@ export class MatTimepickerToggle { * otherwise returns the default aria-label using the timepicker's panelId. */ getAriaLabel(): string { - return this.ariaLabel() || this.defaultAriaLabel; + return this.ariaLabel() || this._defaultAriaLabel; } } From 6f6033582191f0102e90ba4f1d7b7672c76fd2ae Mon Sep 17 00:00:00 2001 From: Joy Serquina Date: Thu, 9 Jan 2025 17:44:27 +0000 Subject: [PATCH 4/5] build(material/timepicker): updates api goldens Ran command to update api goldens. --- tools/public_api_guard/material/timepicker.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/public_api_guard/material/timepicker.md b/tools/public_api_guard/material/timepicker.md index 528d217bd53f..472a71f3901d 100644 --- a/tools/public_api_guard/material/timepicker.md +++ b/tools/public_api_guard/material/timepicker.md @@ -124,15 +124,17 @@ export interface MatTimepickerSelected { // @public export class MatTimepickerToggle { readonly ariaLabel: InputSignal; + readonly ariaLabelledby: InputSignal; readonly disabled: InputSignalWithTransform; readonly disableRipple: InputSignalWithTransform; + getAriaLabel(): string; // (undocumented) protected _isDisabled: Signal; protected _open(event: Event): void; readonly tabIndex: InputSignal; readonly timepicker: InputSignal>; // (undocumented) - static ɵcmp: i0.ɵɵComponentDeclaration, "mat-timepicker-toggle", ["matTimepickerToggle"], { "timepicker": { "alias": "for"; "required": true; "isSignal": true; }; "ariaLabel": { "alias": "aria-label"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "tabIndex": { "alias": "tabIndex"; "required": false; "isSignal": true; }; "disableRipple": { "alias": "disableRipple"; "required": false; "isSignal": true; }; }, {}, never, ["[matTimepickerToggleIcon]"], true, never>; + static ɵcmp: i0.ɵɵComponentDeclaration, "mat-timepicker-toggle", ["matTimepickerToggle"], { "timepicker": { "alias": "for"; "required": true; "isSignal": true; }; "ariaLabel": { "alias": "aria-label"; "required": false; "isSignal": true; }; "ariaLabelledby": { "alias": "aria-labelledby"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "tabIndex": { "alias": "tabIndex"; "required": false; "isSignal": true; }; "disableRipple": { "alias": "disableRipple"; "required": false; "isSignal": true; }; }, {}, never, ["[matTimepickerToggleIcon]"], true, never>; // (undocumented) static ɵfac: i0.ɵɵFactoryDeclaration, never>; } From fc37006260c72b8d2ec89ee04bd561d1cc61b27b Mon Sep 17 00:00:00 2001 From: Joy Serquina Date: Fri, 10 Jan 2025 18:13:05 +0000 Subject: [PATCH 5/5] refactor(material/timepicker): adds check for aria-labelledby for override Updates previous fix which implements a default aria-label if no custom aria-label is provided to where it checks if an aria-lablledby value is provided and uses the aria-labelledby value if available. If not it will check for a custom aria-label and if that is not provided it will default to the generic aria-label value. --- src/material/timepicker/timepicker-toggle.ts | 9 ++++----- tools/public_api_guard/material/timepicker.md | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/material/timepicker/timepicker-toggle.ts b/src/material/timepicker/timepicker-toggle.ts index 193959bb841c..1bf7a67fcdad 100644 --- a/src/material/timepicker/timepicker-toggle.ts +++ b/src/material/timepicker/timepicker-toggle.ts @@ -94,11 +94,10 @@ export class MatTimepickerToggle { } /** - * Gets the aria-label to use for the toggle button. - * Returns the user-provided aria-label if one exists, - * otherwise returns the default aria-label using the timepicker's panelId. + * Checks for ariaLabelledby and if empty uses custom + * aria-label or defaultAriaLabel if neither is provided. */ - getAriaLabel(): string { - return this.ariaLabel() || this._defaultAriaLabel; + getAriaLabel(): string | null { + return this.ariaLabelledby() ? null : this.ariaLabel() || this._defaultAriaLabel; } } diff --git a/tools/public_api_guard/material/timepicker.md b/tools/public_api_guard/material/timepicker.md index 472a71f3901d..d99141df8ddc 100644 --- a/tools/public_api_guard/material/timepicker.md +++ b/tools/public_api_guard/material/timepicker.md @@ -127,7 +127,7 @@ export class MatTimepickerToggle { readonly ariaLabelledby: InputSignal; readonly disabled: InputSignalWithTransform; readonly disableRipple: InputSignalWithTransform; - getAriaLabel(): string; + getAriaLabel(): string | null; // (undocumented) protected _isDisabled: Signal; protected _open(event: Event): void;