diff --git a/modules/react/text-area/stories/TextArea.mdx b/modules/react/text-area/stories/TextArea.mdx index d03f4ae0cc..a6ce25ff1a 100644 --- a/modules/react/text-area/stories/TextArea.mdx +++ b/modules/react/text-area/stories/TextArea.mdx @@ -110,33 +110,207 @@ examples and accessibility guidance. ## Accessibility -`TextArea` should be used with [Form Field](/components/inputs/form-field/) to -ensure proper labeling, error handling, and help text association. See -[FormField's accessibility documentation](/components/inputs/form-field/#accessibility) -for comprehensive guidance on form accessibility best practices. +The primary accessibility goal for `TextArea` is to give every user a visible, persistent label and +clear instructions, and to ensure assistive technology users can identify the multi-line field and +hear hints, errors, required state, and character-limit information when the control receives focus. + +### Minimum accessible structure + +Match the Basic example: label first, then the input inside `FormField.Field`. This order matches the +DOM reading sequence and ensures the label's `htmlFor` targets the ` + +``` + +When hint text is present: + +```html +
+ + +

Share any additional feedback.

+
+``` + +For a field in an error state: + +```html +
+ + +

Error: Please enter at least 10 characters.

+
+``` -### Character Limits +### Accessibility Requirements -When limiting text area length: +Required in application code for an accessible `TextArea`. Rows marked _(conditional)_ apply only when +the situation matches—otherwise omit. -- Use the `maxLength` attribute to enforce the limit programmatically. -- For longer limits (100+ characters), consider adding character count information to - `FormField.Hint`. -- Avoid announcing character counts after every keystroke, as this disrupts screen reader users. - Check out - [Debouncing an AriaLiveRegion: TextArea with character limit](https://workday.github.io/canvas-kit/?path=/docs/guides-accessibility-aria-live-regions--docs#debouncing-an-arialiveregion-textarea-with-character-limit) - for an example of how to wait for users to stop typing before announcing the character count to - screen readers. +**If no design spec is provided:** use a visible `FormField.Label`, wrap the control with +`FormField.Input as={TextArea}`, omit `isHidden`, keep default `resize: both`, and omit a custom `id` +unless testing or composition requires it. -### Screen Reader Experience +**Character limit with debounced live region** _(conditional — when `maxLength` is set)_: -When properly implemented with `FormField`, screen readers will announce: +```tsx +import {AccessibleHide, AriaLiveRegion} from '@workday/canvas-kit-react/common'; +import {FormField} from '@workday/canvas-kit-react/form-field'; +import {TextArea} from '@workday/canvas-kit-react/text-area'; + +const MAX_CHARACTERS = 200; + + + Comments + + + {`${value.length} of ${MAX_CHARACTERS} characters`} + {liveUpdateStr} + +; +``` + +Debounce live-region updates (for example, 2 seconds after typing stops). Announce immediately when +the limit is reached. Clear the live region on blur. Do not announce character counts after every +keystroke. See +[Debouncing an AriaLiveRegion: TextArea with character limit](?path=/docs/guides-accessibility-aria-live-regions--docs#debouncing-an-arialiveregion-textarea-with-character-limit) +for a full example. + +**Ref forwarding** _(conditional — when programmatic focus is needed)_: + +```tsx +const ref = React.useRef(null); + +; +``` -- The label text when the text area receives focus. -- Required, disabled, or read-only status. -- Help text and error messages (via `aria-describedby`). -- The current value or "blank" if empty. -- That it's a multi-line text input field. +| Requirement | How to satisfy | +| --- | --- | +| Visible label | **`FormField.Label`** with concise, meaningful text | +| Input wiring | **`FormField.Input as={TextArea}`** wrapping every `TextArea` instance | +| Hint or error text _(conditional)_ | **`FormField.Hint`** when there is help or validation copy—required because `aria-describedby` is wired by default (see **Built-in Behaviors**) | +| Error state _(conditional)_ | `error="error"` on **`FormField`** and **`FormField.Hint`** prefixed with "Error:" so users who cannot perceive color can distinguish errors from hints | +| Caution state _(conditional)_ | `error="caution"` on **`FormField`** with descriptive **`FormField.Hint`** (no `aria-invalid`) | +| Required field _(conditional)_ | `isRequired` on **`FormField`**; consider a form-level note that asterisk (\*) marks required fields | +| Disabled field _(conditional)_ | `disabled` on **`FormField.Input`** (passed through to `