tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 42718c5fca6a275b9ea0ad07b532a139ffe2f499
parent 5a074abbc342e1a9544820c98e0c31a4245e6c22
Author: Anna Kulyk <akulyk@mozilla.com>
Date:   Mon, 13 Oct 2025 18:47:27 +0000

Bug 1992462 - Support aria-description in moz- input widgets r=tgiles,accessibility-frontend-reviewers,morgan

Differential Revision: https://phabricator.services.mozilla.com/D267640

Diffstat:
Mtoolkit/content/tests/widgets/lit-test-helpers.js | 32++++++++++++++++++++++++++++++++
Mtoolkit/content/widgets/lit-utils.mjs | 5+++--
Mtoolkit/content/widgets/moz-checkbox/moz-checkbox.mjs | 7++++++-
Mtoolkit/content/widgets/moz-input-search/moz-input-search.mjs | 6+++++-
Mtoolkit/content/widgets/moz-input-text/moz-input-text.mjs | 5+++++
Mtoolkit/content/widgets/moz-radio-group/moz-radio-group.mjs | 7++++++-
Mtoolkit/content/widgets/moz-select/moz-select.mjs | 7++++++-
Mtoolkit/content/widgets/moz-toggle/moz-toggle.mjs | 9++++++---
8 files changed, 69 insertions(+), 9 deletions(-)

diff --git a/toolkit/content/tests/widgets/lit-test-helpers.js b/toolkit/content/tests/widgets/lit-test-helpers.js @@ -167,6 +167,7 @@ class InputTestHelpers extends LitTestHelpers { async testCommonInputProperties(elementName) { await this.verifyLabel(elementName); await this.verifyAriaLabel(elementName); + await this.verifyAriaDescription(elementName); await this.verifyName(elementName); await this.verifyValue(elementName); await this.verifyIcon(elementName); @@ -794,6 +795,11 @@ class InputTestHelpers extends LitTestHelpers { ]); } + /** + * Verifies that the aria-label attribute is applied to the input element. + * + * @param {string} selector - HTML tag of the element under test. + */ async verifyAriaLabel(selector) { const ARIA_LABEL = "I'm not visible"; let ariaLabelTemplate = this.templateFn({ @@ -817,6 +823,32 @@ class InputTestHelpers extends LitTestHelpers { } /** + * Verifies that the aria-description attribute is applied to the input element. + * + * @param {string} selector - HTML tag of the element under test. + */ + async verifyAriaDescription(selector) { + const ARIA_DESCRIPTION = "I'm not visible"; + let ariaDescriptionTemplate = this.templateFn({ + value: "default", + "aria-description": ARIA_DESCRIPTION, + }); + let renderTarget = await this.renderTemplate(ariaDescriptionTemplate); + let input = renderTarget.querySelector(selector); + + ok(!input.hasDescription, "No visible description text is rendered."); + ok( + !input.getAttribute("aria-description"), + "aria-description is not set on the outer element." + ); + is( + input.inputEl.getAttribute("aria-description"), + ARIA_DESCRIPTION, + "The aria-description is set on the input element." + ); + } + + /** * Verifies the behavior of nested elements for inputs that support nesting. * * @param {string} selector - HTML tag of the element under test. diff --git a/toolkit/content/widgets/lit-utils.mjs b/toolkit/content/widgets/lit-utils.mjs @@ -242,8 +242,8 @@ export class MozLitElement extends LitElement { * @property {boolean} parentDisabled - When this element is nested under another input and that * input is disabled or unchecked/unpressed the parent will set this property to true so this * element can be disabled. - * @property {string} ariaLabel - * The aria-label text for cases where there is no visible label. + * @property {string} ariaLabel - The aria-label text when there is no visible label. + * @property {string} ariaDescription - The aria-description text when there is no visible description. */ export class MozBaseInputElement extends MozLitElement { #internals; @@ -260,6 +260,7 @@ export class MozBaseInputElement extends MozLitElement { accessKey: { type: String, mapped: true, fluent: true }, parentDisabled: { type: Boolean, state: true }, ariaLabel: { type: String, mapped: true }, + ariaDescription: { type: String, mapped: true }, }; static inputLayout = "inline"; diff --git a/toolkit/content/widgets/moz-checkbox/moz-checkbox.mjs b/toolkit/content/widgets/moz-checkbox/moz-checkbox.mjs @@ -24,6 +24,8 @@ import "chrome://global/content/elements/moz-support-link.mjs"; * @property {string} iconSrc - The src for an optional icon * @property {string} description - The text for the description element that helps describe the checkbox * @property {string} supportPage - Name of the SUMO support page to link to. + * @property {string} ariaLabel - The aria-label text when there is no visible label. + * @property {string} ariaDescription - The aria-description text when there is no visible description. */ export default class MozCheckbox extends MozBaseInputElement { static properties = { @@ -57,8 +59,11 @@ export default class MozCheckbox extends MozBaseInputElement { @click=${this.handleStateChange} @change=${this.redispatchEvent} ?disabled=${this.disabled || this.parentDisabled} - aria-describedby="description" aria-label=${ifDefined(this.ariaLabel ?? undefined)} + aria-describedby="description" + aria-description=${ifDefined( + this.hasDescription ? undefined : this.ariaDescription + )} accesskey=${ifDefined(this.accessKey)} />`; } diff --git a/toolkit/content/widgets/moz-input-search/moz-input-search.mjs b/toolkit/content/widgets/moz-input-search/moz-input-search.mjs @@ -17,7 +17,8 @@ import MozInputText from "chrome://global/content/elements/moz-input-text.mjs"; * @property {string} description - The text for the description element that helps describe the input control * @property {string} supportPage - Name of the SUMO support page to link to. * @property {string} placeholder - Text to display when the input has no value. - * @property {string} ariaLabel - The aria-label text for cases where there is no visible label. + * @property {string} ariaLabel - The aria-label text when there is no visible label. + * @property {string} ariaDescription - The aria-description text when there is no visible description. */ export default class MozInputSearch extends MozInputText { // The amount of milliseconds that we wait before firing the "search" event. @@ -86,6 +87,9 @@ export default class MozInputSearch extends MozInputText { placeholder=${ifDefined(this.placeholder)} aria-label=${ifDefined(this.ariaLabel ?? undefined)} aria-describedby="description" + aria-description=${ifDefined( + this.hasDescription ? undefined : this.ariaDescription + )} @input=${this.handleInput} @change=${this.redispatchEvent} /> diff --git a/toolkit/content/widgets/moz-input-text/moz-input-text.mjs b/toolkit/content/widgets/moz-input-text/moz-input-text.mjs @@ -18,6 +18,8 @@ import { MozBaseInputElement } from "../lit-utils.mjs"; * @property {string} description - The text for the description element that helps describe the input control * @property {string} supportPage - Name of the SUMO support page to link to. * @property {string} placeholder - Text to display when the input has no value. + * @property {string} ariaLabel - The aria-label text when there is no visible label. + * @property {string} ariaDescription - The aria-description text when there is no visible description. */ export default class MozInputText extends MozBaseInputElement { static properties = { @@ -60,6 +62,9 @@ export default class MozInputText extends MozBaseInputElement { placeholder=${ifDefined(this.placeholder)} aria-label=${ifDefined(this.ariaLabel ?? undefined)} aria-describedby="description" + aria-description=${ifDefined( + this.hasDescription ? undefined : this.ariaDescription + )} @input=${this.handleInput} @change=${this.redispatchEvent} /> diff --git a/toolkit/content/widgets/moz-radio-group/moz-radio-group.mjs b/toolkit/content/widgets/moz-radio-group/moz-radio-group.mjs @@ -24,6 +24,8 @@ import { MozBaseInputElement } from "../lit-utils.mjs"; * @property {string} value * Selected value for the group. Changing the value updates the checked * state of moz-radio children and vice versa. + * @property {string} ariaLabel - The aria-label text when there is no visible label. + * @property {string} ariaDescription - The aria-description text when there is no visible description. * @slot default - The radio group's content, intended for moz-radio elements. * @slot support-link - The radio group's support link intended for moz-radio elements. */ @@ -69,11 +71,14 @@ export class MozRadio extends SelectControlItemMixin(MozBaseInputElement) { name=${this.name} .checked=${this.checked} aria-checked=${this.checked} - aria-describedby="description" tabindex=${this.itemTabIndex} ?disabled=${this.isDisabled} accesskey=${ifDefined(this.accessKey)} aria-label=${ifDefined(this.ariaLabel ?? undefined)} + aria-describedby="description" + aria-description=${ifDefined( + this.hasDescription ? undefined : this.ariaDescription + )} @click=${this.handleClick} @change=${this.handleChange} />`; diff --git a/toolkit/content/widgets/moz-select/moz-select.mjs b/toolkit/content/widgets/moz-select/moz-select.mjs @@ -22,6 +22,8 @@ import { MozBaseInputElement, MozLitElement } from "../lit-utils.mjs"; * @property {string} iconSrc - The src for an optional icon * @property {string} description - The text for the description element that helps describe the input control * @property {string} supportPage - Name of the SUMO support page to link to. + * @property {string} ariaLabel - The aria-label text when there is no visible label. + * @property {string} ariaDescription - The aria-description text when there is no visible description. * @property {array} options - The array of options, populated by <moz-option> children in the * default slot. Do not set directly, these will be overridden by <moz-option> children. */ @@ -141,8 +143,11 @@ export default class MozSelect extends MozBaseInputElement { @input=${this.handleStateChange} @change=${this.redispatchEvent} ?disabled=${this.disabled || this.parentDisabled} - aria-describedby="description" aria-label=${ifDefined(this.ariaLabel ?? undefined)} + aria-describedby="description" + aria-description=${ifDefined( + this.hasDescription ? undefined : this.ariaDescription + )} > ${this.options.map( option => html` diff --git a/toolkit/content/widgets/moz-toggle/moz-toggle.mjs b/toolkit/content/widgets/moz-toggle/moz-toggle.mjs @@ -15,8 +15,8 @@ import "chrome://global/content/elements/moz-label.mjs"; * @property {boolean} disabled - Whether or not the element is disabled. * @property {string} label - The label text. * @property {string} description - The description text. - * @property {string} ariaLabel - * The aria-label text for cases where there is no visible label. + * @property {string} ariaLabel - The aria-label text when there is no visible label. + * @property {string} ariaDescription - The aria-description text when there is no visible description. * @slot support-link - Used to append a moz-support-link to the description. * @fires toggle * Custom event indicating that the toggle's pressed state has changed. @@ -58,8 +58,11 @@ export default class MozToggle extends MozBaseInputElement { value=${this.value} ?disabled=${disabled} aria-pressed=${pressed} - aria-describedby="description" aria-label=${ifDefined(ariaLabel ?? undefined)} + aria-describedby="description" + aria-description=${ifDefined( + this.hasDescription ? undefined : this.ariaDescription + )} accesskey=${ifDefined(this.accessKey)} @click=${handleClick} ></button>`;