From 86cfe5ad14143234d9fba4076ad09148364800eb Mon Sep 17 00:00:00 2001 From: Georgi Damyanov Date: Mon, 6 Apr 2026 15:35:03 +0300 Subject: [PATCH 1/2] feat: add aria-describedby attribute for readonly state --- packages/main/cypress/specs/Switch.cy.tsx | 24 +++++++++++++++++++++++ packages/main/src/Switch.ts | 9 +++++++++ packages/main/src/SwitchTemplate.tsx | 3 +++ packages/main/src/themes/Switch.css | 6 ++++-- 4 files changed, 40 insertions(+), 2 deletions(-) diff --git a/packages/main/cypress/specs/Switch.cy.tsx b/packages/main/cypress/specs/Switch.cy.tsx index 2b9f7ed1a69b..7d805b20fa38 100644 --- a/packages/main/cypress/specs/Switch.cy.tsx +++ b/packages/main/cypress/specs/Switch.cy.tsx @@ -191,6 +191,30 @@ describe("General accesibility attributes", () => { cy.get("[ui5-switch]") .ui5SwitchCheckAttributeInShadowDomRoot("aria-required", "false"); }); + + it("Should have 'aria-describedby' attribute when readonly", () => { + cy.mount(); + + cy.get("[ui5-switch]") + .then($switch => { + const switchId = ($switch.get(0) as Switch)._id; + const expectedDescribedBy = `${switchId}-readonly-desc`; + + cy.wrap($switch) + .ui5SwitchCheckAttributeInShadowDomRoot("aria-describedby", expectedDescribedBy); + }); + }); + + it("Should not have 'aria-describedby' attribute when not readonly", () => { + cy.mount(); + + cy.mount(); + + cy.get("[ui5-switch]") + .shadow() + .find(".ui5-switch-root") + .should("not.have.attr", "aria-describedby"); + }); }); describe("General interactions in form", () => { diff --git a/packages/main/src/Switch.ts b/packages/main/src/Switch.ts index 27a873eb26b6..e5896da64728 100644 --- a/packages/main/src/Switch.ts +++ b/packages/main/src/Switch.ts @@ -19,6 +19,7 @@ import { FORM_CHECKABLE_REQUIRED, SWITCH_ON, SWITCH_OFF, + ACC_STATE_READONLY, } from "./generated/i18n/i18n-defaults.js"; // Template @@ -364,6 +365,14 @@ class Switch extends UI5Element implements IFormInputElement { get ariaLabelText() { return getEffectiveAriaLabelText(this) || getAssociatedLabelForTexts(this) || undefined; } + + get ariaDescribedBy() { + return this.readonly ? `${this._id}-readonly-desc` : undefined; + } + + get ariaDescribedByText() { + return this.readonly ? Switch.i18nBundle.getText(ACC_STATE_READONLY) : ""; + } } Switch.define(); diff --git a/packages/main/src/SwitchTemplate.tsx b/packages/main/src/SwitchTemplate.tsx index 9f565a584017..3c2598f1738b 100644 --- a/packages/main/src/SwitchTemplate.tsx +++ b/packages/main/src/SwitchTemplate.tsx @@ -22,6 +22,7 @@ export default function SwitchTemplate(this: Switch) { aria-disabled={this.effectiveAriaDisabled} aria-readonly={this.effectiveAriaReadonly} aria-required={this.required} + aria-describedby={this.ariaDescribedBy} onClick={this._onclick} onKeyUp={this._onkeyup} onKeyDown={this._onkeydown} @@ -61,6 +62,8 @@ export default function SwitchTemplate(this: Switch) { } + {this.readonly && {this.ariaDescribedByText}} + diff --git a/packages/main/src/themes/Switch.css b/packages/main/src/themes/Switch.css index 6801fcc9f021..0c177c47b094 100644 --- a/packages/main/src/themes/Switch.css +++ b/packages/main/src/themes/Switch.css @@ -145,10 +145,12 @@ cursor: default; } -.ui5-switch-root.ui5-switch--checked .ui5-switch-text--off { +.ui5-switch-root.ui5-switch--checked .ui5-switch-text--off, +.ui5-switch-root.ui5-switch--checked .ui5-switch-text--readonly { visibility: var(--_ui5_switch_text_hidden); } -.ui5-switch-root:not(.ui5-switch--checked) .ui5-switch-text--on { +.ui5-switch-root:not(.ui5-switch--checked) .ui5-switch-text--on, +.ui5-switch-root:not(.ui5-switch--checked) .ui5-switch-text--readonly { visibility: var(--_ui5_switch_text_hidden); } From 8591fc84f165100625a4672e91141958ae7f7cf2 Mon Sep 17 00:00:00 2001 From: Georgi Damyanov Date: Tue, 14 Apr 2026 16:52:46 +0300 Subject: [PATCH 2/2] refactor: remove unused part --- packages/main/src/SwitchTemplate.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/main/src/SwitchTemplate.tsx b/packages/main/src/SwitchTemplate.tsx index 3c2598f1738b..280ff4a7c03e 100644 --- a/packages/main/src/SwitchTemplate.tsx +++ b/packages/main/src/SwitchTemplate.tsx @@ -62,7 +62,7 @@ export default function SwitchTemplate(this: Switch) { } - {this.readonly && {this.ariaDescribedByText}} + {this.readonly && {this.ariaDescribedByText}}