From d8200f0c2813937b1d7538ed642630e37eaa8c7f Mon Sep 17 00:00:00 2001 From: Nikola Anachkov Date: Tue, 28 Apr 2026 16:38:52 +0300 Subject: [PATCH] feat(ui5-list): add live region announcement for item selection (POC) Announces "Selected" or "Not Selected" via InvisibleMessage when a list item's selection state changes in any selectionMode other than "None". Covers Single, SingleStart, SingleEnd, SingleAuto, and Multiple modes. --- packages/main/cypress/specs/List.cy.tsx | 58 +++++++++++++++++++++++++ packages/main/src/List.ts | 10 +++++ 2 files changed, 68 insertions(+) diff --git a/packages/main/cypress/specs/List.cy.tsx b/packages/main/cypress/specs/List.cy.tsx index 0e3acd85315d..529cca25887b 100644 --- a/packages/main/cypress/specs/List.cy.tsx +++ b/packages/main/cypress/specs/List.cy.tsx @@ -457,6 +457,64 @@ describe("List - Accessibility", () => { }); }); }); + + it("announces 'Selected' when an item is selected in Single mode", () => { + cy.mount( + + Argentina + Bulgaria + + ); + + cy.get(".ui5-invisiblemessage-polite").as("liveRegion"); + + cy.get("#item1").realClick(); + cy.get("@liveRegion").should("contain.text", "Selected"); + }); + + it("announces 'Selected' and 'Not Selected' when items are toggled in Multiple mode", () => { + cy.mount( + + Argentina + Bulgaria + + ); + + cy.get(".ui5-invisiblemessage-polite").as("liveRegion"); + + cy.get("#item1").realClick(); + cy.get("@liveRegion").should("contain.text", "Selected"); + + cy.get("#item1").realClick(); + cy.get("@liveRegion").should("contain.text", "Not Selected"); + }); + + it("does not announce selection when selectionMode is None", () => { + cy.mount( + + Argentina + + ); + + cy.get(".ui5-invisiblemessage-polite").as("liveRegion"); + + cy.get("#item1").realClick(); + cy.get("@liveRegion").should("have.text", ""); + }); + + it("does not announce selection when selection-change event is prevented", () => { + cy.mount( + e.preventDefault()}> + Argentina + Bulgaria + + ); + + cy.get(".ui5-invisiblemessage-polite").as("liveRegion"); + + cy.get("#item1").realClick(); + cy.get("@liveRegion").should("have.text", ""); + }); }); describe("List - Wrapping Behavior", () => { diff --git a/packages/main/src/List.ts b/packages/main/src/List.ts index 4ce0a29f3332..893db6d51fc8 100644 --- a/packages/main/src/List.ts +++ b/packages/main/src/List.ts @@ -38,6 +38,8 @@ import { getAllAccessibleNameRefTexts, } from "@ui5/webcomponents-base/dist/util/AccessibilityTextsHelper.js"; import getNormalizedTarget from "@ui5/webcomponents-base/dist/util/getNormalizedTarget.js"; +import announce from "@ui5/webcomponents-base/dist/util/InvisibleMessage.js"; +import InvisibleMessageMode from "@ui5/webcomponents-base/dist/types/InvisibleMessageMode.js"; import type I18nBundle from "@ui5/webcomponents-base/dist/i18nBundle.js"; import debounce from "@ui5/webcomponents-base/dist/util/debounce.js"; import isElementInView from "@ui5/webcomponents-base/dist/util/isElementInView.js"; @@ -70,6 +72,8 @@ import { LOAD_MORE_TEXT, ARIA_LABEL_LIST_SELECTABLE, ARIA_LABEL_LIST_MULTISELECTABLE, ARIA_LABEL_LIST_DELETABLE, + LIST_ITEM_SELECTED, + LIST_ITEM_NOT_SELECTED, } from "./generated/i18n/i18n-defaults.js"; import type CheckBox from "./CheckBox.js"; import type RadioButton from "./RadioButton.js"; @@ -917,6 +921,12 @@ class List extends UI5Element { }); if (changePrevented) { this._revertSelection(previouslySelectedItems); + } else { + const item = e.detail.item; + const selectedText = item.selected + ? List.i18nBundle.getText(LIST_ITEM_SELECTED) + : List.i18nBundle.getText(LIST_ITEM_NOT_SELECTED); + announce(selectedText, InvisibleMessageMode.Polite); } } }