diff --git a/packages/fiori/cypress/specs/UserSettingsDialog.cy.tsx b/packages/fiori/cypress/specs/UserSettingsDialog.cy.tsx
index 9db3e7df18d46..3ffd2e451b856 100644
--- a/packages/fiori/cypress/specs/UserSettingsDialog.cy.tsx
+++ b/packages/fiori/cypress/specs/UserSettingsDialog.cy.tsx
@@ -509,6 +509,64 @@ describe("Events", () => {
cy.get("@search").should("have.attr", "placeholder", "Search");
cy.get("@search").shadow().find("input").type("test");
});
+
+ it("tests search results announcement - no results", () => {
+ cy.mount(
+
+
+ );
+
+ cy.get("[ui5-user-settings-dialog]").as("settings");
+ cy.get("@settings").shadow().find("[ui5-dialog]").as("dialog");
+ cy.get("@dialog").find("[ui5-input]").as("search");
+
+ cy.get(".ui5-invisiblemessage-polite")
+ .as("invisibleMessage")
+ .should("have.text", "");
+
+ cy.get("@search").shadow().find("input").type("zzz");
+
+ cy.get("@invisibleMessage").should("have.text", "No search results");
+ });
+
+ it("tests search results announcement - one result", () => {
+ cy.mount(
+
+
+ );
+
+ cy.get("[ui5-user-settings-dialog]").as("settings");
+ cy.get("@settings").shadow().find("[ui5-dialog]").as("dialog");
+ cy.get("@dialog").find("[ui5-input]").as("search");
+
+ cy.get(".ui5-invisiblemessage-polite")
+ .as("invisibleMessage")
+ .should("have.text", "");
+
+ cy.get("@search").shadow().find("input").type("Payment");
+
+ cy.get("@invisibleMessage").should("have.text", "1 result available");
+ });
+
+ it("tests search results announcement - multiple results", () => {
+ cy.mount(
+
+
+
+ );
+
+ cy.get("[ui5-user-settings-dialog]").as("settings");
+ cy.get("@settings").shadow().find("[ui5-dialog]").as("dialog");
+ cy.get("@dialog").find("[ui5-input]").as("search");
+
+ cy.get(".ui5-invisiblemessage-polite")
+ .as("invisibleMessage")
+ .should("have.text", "");
+
+ cy.get("@search").shadow().find("input").type("Pay");
+
+ cy.get("@invisibleMessage").should("have.text", "2 results are available");
+ });
});
describe("Responsiveness", () => {
diff --git a/packages/fiori/src/UserSettingsDialog.ts b/packages/fiori/src/UserSettingsDialog.ts
index 3edd22591a817..310de63622c6a 100644
--- a/packages/fiori/src/UserSettingsDialog.ts
+++ b/packages/fiori/src/UserSettingsDialog.ts
@@ -13,6 +13,8 @@ import type ListItemBase from "@ui5/webcomponents/dist/ListItemBase.js";
import type { PopupBeforeCloseEventDetail } from "@ui5/webcomponents/dist/Popup.js";
import { isPhone, isTablet, isCombi } from "@ui5/webcomponents-base/dist/Device.js";
import MediaRange from "@ui5/webcomponents-base/dist/MediaRange.js";
+import announce from "@ui5/webcomponents-base/dist/util/InvisibleMessage.js";
+import InvisibleMessageMode from "@ui5/webcomponents-base/dist/types/InvisibleMessageMode.js";
import UserSettingsDialogTemplate from "./UserSettingsDialogTemplate.js";
import type UserSettingsItem from "./UserSettingsItem.js";
import UserSettingsDialogCss from "./generated/themes/UserSettingsDialog.css.js";
@@ -25,6 +27,9 @@ import {
USER_SETTINGS_DIALOG_SAVE_BUTTON_TEXT,
USER_SETTINGS_DIALOG_CANCEL_BUTTON_TEXT,
USER_SETTINGS_DIALOG_NO_SEARCH_RESULTS_TEXT,
+ USER_SETTINGS_DIALOG_SEARCH_NO_RESULTS,
+ USER_SETTINGS_DIALOG_SEARCH_ONE_RESULT,
+ USER_SETTINGS_DIALOG_SEARCH_MORE_RESULTS,
} from "./generated/i18n/i18n-defaults.js";
type UserSettingsItemSelectEventDetail = {
@@ -223,6 +228,13 @@ class UserSettingsDialog extends UI5Element {
@property({ type: Boolean })
_showNoSearchResult = false;
+ /**
+ * Indicates that the user changed the search value and the search
+ * results should be announced on the next rendering.
+ * @private
+ */
+ _announceSearchResults = false;
+
/**
* Defines the current media query size.
* @private
@@ -269,6 +281,11 @@ class UserSettingsDialog extends UI5Element {
this._showNoSearchResult = false;
}
+ if (this._announceSearchResults) {
+ this._announceSearchResults = false;
+ announce(this._searchResultsText, InvisibleMessageMode.Polite);
+ }
+
if (!this._selectedSetting) {
this._selectedSetting = this.items[0] || this.fixedItems[0];
}
@@ -344,6 +361,19 @@ class UserSettingsDialog extends UI5Element {
return UserSettingsDialog.i18nBundle.getText(USER_SETTINGS_DIALOG_NO_SEARCH_RESULTS_TEXT);
}
+ get _searchResultsText() {
+ const resultsCount = this._filteredItems.length + this._filteredFixedItems.length;
+
+ switch (resultsCount) {
+ case 0:
+ return UserSettingsDialog.i18nBundle.getText(USER_SETTINGS_DIALOG_SEARCH_NO_RESULTS);
+ case 1:
+ return UserSettingsDialog.i18nBundle.getText(USER_SETTINGS_DIALOG_SEARCH_ONE_RESULT);
+ default:
+ return UserSettingsDialog.i18nBundle.getText(USER_SETTINGS_DIALOG_SEARCH_MORE_RESULTS, resultsCount);
+ }
+ }
+
get _selectedItemSlotName() {
return this._selectedSetting ? this._selectedSetting._individualSlot : "";
}
@@ -374,6 +404,7 @@ class UserSettingsDialog extends UI5Element {
_handleInput(e: CustomEvent) {
this._searchValue = (e.target as Input).value;
+ this._announceSearchResults = true;
}
captureRef(ref: HTMLElement & { associatedSettingItem?: UI5Element} | null) {
diff --git a/packages/fiori/src/i18n/messagebundle.properties b/packages/fiori/src/i18n/messagebundle.properties
index 2397251013b95..eeac8c1e8d6bf 100644
--- a/packages/fiori/src/i18n/messagebundle.properties
+++ b/packages/fiori/src/i18n/messagebundle.properties
@@ -614,6 +614,15 @@ USER_SETTINGS_DIALOG_CANCEL_BUTTON_TEXT=Cancel
#XTXT: User settings dialog not result text
USER_SETTINGS_DIALOG_NO_SEARCH_RESULTS_TEXT=No search results
+#XACT: ARIA announcement for the User Settings Dialog search result if no hit
+USER_SETTINGS_DIALOG_SEARCH_NO_RESULTS=No search results
+
+#XACT: ARIA announcement for the User Settings Dialog search result if one hit
+USER_SETTINGS_DIALOG_SEARCH_ONE_RESULT=1 result available
+
+#XACT: ARIA announcement for the User Settings Dialog search result if more than one hit ({0} is the number of hits)
+USER_SETTINGS_DIALOG_SEARCH_MORE_RESULTS={0} results are available
+
#XTXT: User settings account view edit avatar text
USER_SETTINGS_ACCOUNT_EDIT_AVATAR_TXT=Edit avatar