diff --git a/packages/main/cypress/specs/Avatar.cy.tsx b/packages/main/cypress/specs/Avatar.cy.tsx
index 49a06abcf724..8d78831fc15b 100644
--- a/packages/main/cypress/specs/Avatar.cy.tsx
+++ b/packages/main/cypress/specs/Avatar.cy.tsx
@@ -5,6 +5,7 @@ import "@ui5/webcomponents-icons/dist/alert.js";
import "@ui5/webcomponents-icons/dist/person-placeholder.js";
import "@ui5/webcomponents-icons/dist/accelerated.js";
import "@ui5/webcomponents-icons/dist/accept.js";
+import "@ui5/webcomponents-icons/dist/edit.js";
import "@ui5/webcomponents-icons/dist/message-error.js";
import "@ui5/webcomponents-icons/dist/information.js";
import "@ui5/webcomponents-icons/dist/ai.js";
@@ -828,6 +829,62 @@ describe("Avatar with Badge", () => {
.should("have.css", "width", "16px");
});
+ it("shows default tooltip from icon accessible name", () => {
+ cy.mount(
+
+
+
+ );
+
+ cy.get("#avatar-with-default-badge-tooltip [ui5-avatar-badge]")
+ .shadow()
+ .find(".ui5-avatar-badge-icon")
+ .then(($icon) => {
+ cy.wrap($icon[0])
+ .invoke("prop", "_id")
+ .then((iconId) => {
+ cy.get("#avatar-with-default-badge-tooltip [ui5-avatar-badge]")
+ .shadow()
+ .find(".ui5-avatar-badge-icon")
+ .shadow()
+ .find(`#${iconId}-tooltip`)
+ .should("contain.text", "Edit");
+ });
+ });
+ });
+
+ it("uses accessibleName as tooltip text when provided", () => {
+ const customTooltip = "Open profile editor";
+
+ cy.mount(
+
+
+
+ );
+
+ cy.get("#avatar-with-custom-badge-tooltip [ui5-avatar-badge]")
+ .shadow()
+ .find(".ui5-avatar-badge-icon")
+ .shadow()
+ .find("title")
+ .should("contain.text", customTooltip);
+ });
+
+ it("does not set badge-level accessible text when icon is invalid", () => {
+ cy.document().then(doc => {
+ const badge = doc.createElement("ui5-avatar-badge") as AvatarBadge & { effectiveAccessibleName?: string };
+ badge.id = "badge-fallback-tooltip";
+ badge.icon = "non-existent-icon-xyz";
+ doc.body.appendChild(badge);
+
+ cy.wait(100).then(() => {
+ expect(badge.effectiveAccessibleName).to.be.undefined;
+ expect(badge.hasAttribute("invalid")).to.be.true;
+ badge.remove();
+ });
+ });
+ });
+
it("hides badge when icon is invalid and shows when valid", () => {
// Test all invalid cases and valid case in one test using direct DOM manipulation
cy.document().then(doc => {
diff --git a/packages/main/src/AvatarBadge.ts b/packages/main/src/AvatarBadge.ts
index 5e0e028cec0e..82f4efd351b2 100644
--- a/packages/main/src/AvatarBadge.ts
+++ b/packages/main/src/AvatarBadge.ts
@@ -1,7 +1,9 @@
import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js";
import customElement from "@ui5/webcomponents-base/dist/decorators/customElement.js";
import property from "@ui5/webcomponents-base/dist/decorators/property.js";
+import i18n from "@ui5/webcomponents-base/dist/decorators/i18n.js";
import jsxRenderer from "@ui5/webcomponents-base/dist/renderer/JsxRenderer.js";
+import type I18nBundle from "@ui5/webcomponents-base/dist/i18nBundle.js";
import { getIconDataSync } from "@ui5/webcomponents-base/dist/asset-registries/Icons.js";
// Template
@@ -10,6 +12,8 @@ import AvatarBadgeTemplate from "./AvatarBadgeTemplate.js";
// Styles
import AvatarBadgeCss from "./generated/themes/AvatarBadge.css.js";
+import { AVATAR_TOOLTIP } from "./generated/i18n/i18n-defaults.js";
+
import ValueState from "@ui5/webcomponents-base/dist/types/ValueState.js";
/**
@@ -61,6 +65,18 @@ class AvatarBadge extends UI5Element {
@property()
icon?: string;
+ /**
+ * Defines the custom text alternative of the badge icon.
+ *
+ * **Note:** If not provided, the badge uses the icon accessible name.
+ * If no icon accessible name is available, a generic fallback text is used.
+ * @default undefined
+ * @public
+ * @since 2.22.0
+ */
+ @property()
+ accessibleName?: string;
+
/**
* Defines the state of the badge, which determines its styling.
*
@@ -83,8 +99,31 @@ class AvatarBadge extends UI5Element {
@property({ type: Boolean })
invalid = false;
+ /**
+ * @private
+ */
+ @property({ noAttribute: true })
+ effectiveAccessibleName?: string;
+
+ @i18n("@ui5/webcomponents")
+ static i18nBundle: I18nBundle;
+
onBeforeRendering() {
- this.invalid = !this.icon || !getIconDataSync(this.icon);
+ const iconData = this.icon ? getIconDataSync(this.icon) : undefined;
+ this.invalid = !this.icon || !iconData;
+
+ if (this.invalid) {
+ this.effectiveAccessibleName = undefined;
+ } else if (this.accessibleName) {
+ // User-provided accessible name takes precedence
+ this.effectiveAccessibleName = this.accessibleName;
+ } else {
+ // Derive from icon name (e.g., "edit" -> "Edit")
+ // If not possible, fall back to i18n "Avatar" text
+ this.effectiveAccessibleName = this.icon
+ ? this.icon.charAt(0).toUpperCase() + this.icon.slice(1)
+ : AvatarBadge.i18nBundle.getText(AVATAR_TOOLTIP);
+ }
}
}
diff --git a/packages/main/src/AvatarBadgeTemplate.tsx b/packages/main/src/AvatarBadgeTemplate.tsx
index d00ffb55cd89..7e52f8669475 100644
--- a/packages/main/src/AvatarBadgeTemplate.tsx
+++ b/packages/main/src/AvatarBadgeTemplate.tsx
@@ -8,7 +8,9 @@ export default function AvatarBadgeTemplate(this: AvatarBadge) {
)}
>
diff --git a/packages/main/test/pages/Avatar.html b/packages/main/test/pages/Avatar.html
index d479905ff841..ae281cf3376c 100644
--- a/packages/main/test/pages/Avatar.html
+++ b/packages/main/test/pages/Avatar.html
@@ -305,6 +305,25 @@
Avatar Badge - With Icons
+
+ Avatar Badge - Tooltip Behavior
+ The badge tooltip is shown by default from the icon semantic text. You can override it with accessible-name.
+
+
+
+
+
+
Default tooltip (icon text)
+
+
+
+
+
+
Custom tooltip (accessible-name)
+
+
+
+
Avatar Badge - Handling Invalid Icon Names
The badge should not be displayed in the following cases:
diff --git a/packages/website/docs/_components_pages/main/Avatar/Avatar.mdx b/packages/website/docs/_components_pages/main/Avatar/Avatar.mdx
index e62351f3b993..4625bff07a9f 100644
--- a/packages/website/docs/_components_pages/main/Avatar/Avatar.mdx
+++ b/packages/website/docs/_components_pages/main/Avatar/Avatar.mdx
@@ -65,6 +65,8 @@ The Avatar can show images.
### With Badge
The Avatar supports visual affordance through badges using the `ui5-avatar-badge` component. Badges can display icons with different value states to indicate status or notifications. **It is recommended to use badges with interactive avatars** for better user experience and accessibility.
+`ui5-avatar-badge` displays an icon tooltip by default, based on the icon semantic text. To provide a custom tooltip text, set the badge `accessible-name` property.
+
### All Variants
diff --git a/packages/website/docs/_samples/main/Avatar/WithBadge/sample.html b/packages/website/docs/_samples/main/Avatar/WithBadge/sample.html
index dcddb57c4692..d18109cfee27 100644
--- a/packages/website/docs/_samples/main/Avatar/WithBadge/sample.html
+++ b/packages/website/docs/_samples/main/Avatar/WithBadge/sample.html
@@ -15,6 +15,10 @@
+
+
+
+
diff --git a/packages/website/docs/_samples/main/Avatar/WithBadge/sample.tsx b/packages/website/docs/_samples/main/Avatar/WithBadge/sample.tsx
index b90484e80594..fb870031a40d 100644
--- a/packages/website/docs/_samples/main/Avatar/WithBadge/sample.tsx
+++ b/packages/website/docs/_samples/main/Avatar/WithBadge/sample.tsx
@@ -12,11 +12,19 @@ const AvatarBadge = createReactComponent(AvatarBadgeClass);
function App() {
return (
- <>
+
);
}