diff --git a/packages/main/cypress/specs/TextArea.cy.tsx b/packages/main/cypress/specs/TextArea.cy.tsx
index 7a3f1c3e9880..6db77dbdf060 100644
--- a/packages/main/cypress/specs/TextArea.cy.tsx
+++ b/packages/main/cypress/specs/TextArea.cy.tsx
@@ -133,6 +133,82 @@ describe("TextArea general interaction", () => {
.find("textarea")
.should("have.attr", "aria-label", attributeValue);
});
+
+ it("Tests accessibleDescription property", () => {
+ const descriptionValue = "This is a direct description";
+
+ cy.mount();
+
+ cy.get("[ui5-textarea]")
+ .shadow()
+ .find("#accessibleDescription")
+ .should("contain.text", descriptionValue);
+
+ cy.get("[ui5-textarea]")
+ .shadow()
+ .find("textarea")
+ .should("have.attr", "aria-describedby")
+ .and("include", "accessibleDescription");
+ });
+
+ it("Tests accessibleDescriptionRef property", () => {
+ const descriptionValue = "External description text";
+
+ cy.mount(
+ <>
+
{descriptionValue}
+
+ >
+ );
+
+ cy.get("[ui5-textarea]")
+ .shadow()
+ .find("#accessibleDescription")
+ .should("contain.text", descriptionValue);
+
+ cy.get("[ui5-textarea]")
+ .shadow()
+ .find("textarea")
+ .should("have.attr", "aria-describedby")
+ .and("include", "accessibleDescription");
+ });
+
+ it("Tests accessibleDescriptionRef with multiple references", () => {
+ const desc1 = "First description";
+ const desc2 = "Second description";
+
+ cy.mount(
+ <>
+ {desc1}
+ {desc2}
+
+ >
+ );
+
+ cy.get("[ui5-textarea]")
+ .shadow()
+ .find("#accessibleDescription")
+ .should("contain.text", desc1)
+ .and("contain.text", desc2);
+ });
+
+ it("Tests accessibleDescriptionRef takes precedence over accessibleDescription", () => {
+ const directDesc = "Direct description";
+ const refDesc = "Referenced description";
+
+ cy.mount(
+ <>
+ {refDesc}
+
+ >
+ );
+
+ cy.get("[ui5-textarea]")
+ .shadow()
+ .find("#accessibleDescription")
+ .should("contain.text", refDesc)
+ .and("not.contain.text", directDesc);
+ });
});
describe("disabled and readonly textarea", () => {
diff --git a/packages/main/src/TextArea.ts b/packages/main/src/TextArea.ts
index 02b03be5d940..1129a86b8f97 100644
--- a/packages/main/src/TextArea.ts
+++ b/packages/main/src/TextArea.ts
@@ -7,7 +7,11 @@ import customElement from "@ui5/webcomponents-base/dist/decorators/customElement
import jsxRenderer from "@ui5/webcomponents-base/dist/renderer/JsxRenderer.js";
import ResizeHandler from "@ui5/webcomponents-base/dist/delegate/ResizeHandler.js";
import type { ResizeObserverCallback } from "@ui5/webcomponents-base/dist/delegate/ResizeHandler.js";
-import { getEffectiveAriaLabelText, getAssociatedLabelForTexts } from "@ui5/webcomponents-base/dist/util/AccessibilityTextsHelper.js";
+import {
+ getEffectiveAriaLabelText,
+ getAssociatedLabelForTexts,
+ getEffectiveAriaDescriptionText,
+} from "@ui5/webcomponents-base/dist/util/AccessibilityTextsHelper.js";
import i18n from "@ui5/webcomponents-base/dist/decorators/i18n.js";
import type I18nBundle from "@ui5/webcomponents-base/dist/i18nBundle.js";
import { isEscape } from "@ui5/webcomponents-base/dist/Keys.js";
@@ -273,6 +277,24 @@ class TextArea extends UI5Element implements IFormInputElement {
@property()
accessibleNameRef?: string;
+ /**
+ * Defines the accessible description of the component.
+ * @default undefined
+ * @public
+ * @since 2.16.0
+ */
+ @property()
+ accessibleDescription?: string;
+
+ /**
+ * Receives id(or many ids) of the elements that describe the textarea.
+ * @default undefined
+ * @public
+ * @since 2.16.0
+ */
+ @property()
+ accessibleDescriptionRef?: string;
+
/**
* @private
*/
@@ -575,8 +597,21 @@ class TextArea extends UI5Element implements IFormInputElement {
return effectiveAriaLabelText;
}
+ get ariaDescriptionText() {
+ return getEffectiveAriaDescriptionText(this);
+ }
+
+ get ariaDescriptionTextId() {
+ return this.ariaDescriptionText ? "accessibleDescription" : "";
+ }
+
get ariaDescribedBy() {
- return this.hasValueState ? `${this._id}-valueStateDesc` : undefined;
+ const ids = [
+ this.hasValueState ? `${this._id}-valueStateDesc` : "",
+ this.ariaDescriptionTextId,
+ ].filter(Boolean).join(" ");
+
+ return ids || undefined;
}
get ariaValueStateHiddenText() {
diff --git a/packages/main/src/TextAreaTemplate.tsx b/packages/main/src/TextAreaTemplate.tsx
index 728a4b6c3e2a..5dbe2e2a4a3a 100644
--- a/packages/main/src/TextAreaTemplate.tsx
+++ b/packages/main/src/TextAreaTemplate.tsx
@@ -51,6 +51,10 @@ export default function TextAreaTemplate(this: TextArea) {
{this._exceededTextProps.exceededText}
}
+ {this.ariaDescriptionText &&
+ {this.ariaDescriptionText}
+ }
+
{this.hasValueState &&
{this.ariaValueStateHiddenText}
}
diff --git a/packages/main/test/pages/TextArea.html b/packages/main/test/pages/TextArea.html
index ca7b9c0f5f72..aa000d6d2b1f 100644
--- a/packages/main/test/pages/TextArea.html
+++ b/packages/main/test/pages/TextArea.html
@@ -215,6 +215,16 @@
+
+ Text Area: Accessible Description
+ This is an external description element
+ Additional description text
+
+
+
+
+
+