diff --git a/docs/api/accessibility.md b/docs/api/accessibility.md index 66e027e3f..40eadd639 100644 --- a/docs/api/accessibility.md +++ b/docs/api/accessibility.md @@ -1,5 +1,56 @@ # Accessibility +## Accessible name + +The **accessible name** is the text that assistive technologies (like screen readers) announce for an element. It answers the question: _"what would a screen reader call this element?"_. For instance, a button showing a trash icon might have the accessible name `"Delete"`, so a screen reader user knows what it does. + +Testing Library uses the accessible name in the [`*ByRole`](./queries.md#by-role) queries `name` option and in the [`toHaveAccessibleName()`](./jest-matchers.md#tohaveaccessiblename) matcher. Combining a role with an accessible name is a **semantic query**: it finds an element by what it is (`button`) and what it is called (`"Delete"`), rather than by its implementation details. This matches how users experience your UI. + +### How the accessible name is computed + +The accessible name is the **first** of these sources to produce a non-empty value. The sources are ordered from highest to lowest importance. An explicit accessibility label that the developer assigned always takes precedence, and the element's own text content is only used when no such label is present. + +1. **`aria-labelledby` / `accessibilityLabelledBy`**: the [`nativeID`](https://reactnative.dev/docs/view#nativeid) (or array of IDs) of other elements, whose text content is joined with spaces in the referenced order. +2. **`aria-label` / `accessibilityLabel`**: an explicit label string on the element. +3. **`alt`** (`Image` only): the image's alternative text. +4. **`placeholder`** (`TextInput` only). +5. **Text content**: the element's own text, collected recursively from its children (see [Text content](#text-content) below). This is the fallback when none of the label sources above are set. + +### Text content + +When falling back to text content, child text is joined as follows: + +- Adjacent inline text (directly inside `Text` elements) is concatenated **without** a separator, matching how it renders on screen. +- Text from separate, non-inline elements, such as sibling `View`s, is joined with a **single space**. + +For example: + +```jsx +render( + + Hello + World + , +); +// Accessible name: "Hello World" +``` + +### Examples + +```jsx +// Explicit label wins over text content + + X + +// Accessible name: "Close dialog" + +// Text content is used when no explicit label is set + + Submit + +// Accessible name: "Submit" +``` + ## `isHiddenFromAccessibility` ```ts diff --git a/docs/api/jest-matchers.md b/docs/api/jest-matchers.md index 8d95f455e..a45bf68b6 100644 --- a/docs/api/jest-matchers.md +++ b/docs/api/jest-matchers.md @@ -175,11 +175,9 @@ expect(element).toHaveAccessibleName( ) ``` -Checks if an element has the specified accessible name. Accepts `string` or `RegExp`, with optional [text match options](./queries.md#text-match-options) like `exact` and `normalizer`. +Checks if an element has the specified [accessible name](./accessibility.md#accessible-name). Accepts `string` or `RegExp`, with optional [text match options](./queries.md#text-match-options) like `exact` and `normalizer`. -The accessible name comes from `aria-labelledby`, `accessibilityLabelledBy`, `aria-label`, and `accessibilityLabel` props. For `Image` elements, the `alt` prop is also used. If none are present, the element's text content is used. - -When `accessibilityLabelledBy` references multiple elements with an array, their text content is joined with spaces in the referenced order and matched as a single accessible name. `aria-labelledby` follows React Native's single `nativeID` value behavior. +See [Accessible name](./accessibility.md#accessible-name) for how the accessible name is derived from an element's label props and text content. Without a `name` parameter (or with `undefined`), it only checks whether the element has any accessible name. diff --git a/docs/api/overview.md b/docs/api/overview.md index d3f38764e..bb0ecb52b 100644 --- a/docs/api/overview.md +++ b/docs/api/overview.md @@ -14,5 +14,5 @@ React Native Testing Library consists of following APIs: - [`renderHook` function](./render-hook.md) - render hooks for testing - [Async utils](./async-utilities.md): `findBy*` queries, `waitFor`, `waitForElementToBeRemoved` - [Configuration](./configuration.md): `configure`, `resetToDefaults` - - [Accessibility](./accessibility.md): `isHiddenFromAccessibility` + - [Accessibility](./accessibility.md): accessible name, `isHiddenFromAccessibility` - [Other](./other-helpers.md): `within`, `act`, `cleanup` diff --git a/docs/api/queries.md b/docs/api/queries.md index 000732e73..7388692a0 100644 --- a/docs/api/queries.md +++ b/docs/api/queries.md @@ -188,7 +188,7 @@ const element3 = screen.getByRole('button', { name: 'Hello', disabled: true }); #### Options -- `name`: Finds an element with given `role`/`accessibilityRole` and an accessible name (= accessability label or text content). +- `name`: Finds an element with given `role`/`accessibilityRole` and a matching [accessible name](./accessibility.md#accessible-name). The accessible name is the text a screen reader would announce for the element, derived from its label props or text content. See [Accessible name](./accessibility.md#accessible-name) for the details. - `disabled`: You can filter elements by their disabled state (coming either from `aria-disabled` prop or `accessbilityState.disabled` prop). The possible values are `true` or `false`. Querying `disabled: false` will also match elements with `disabled: undefined` (see the [wiki](https://github.com/callstack/react-native-testing-library/wiki/Accessibility:-State) for more details). - See [React Native's accessibilityState](https://reactnative.dev/docs/accessibility#accessibilitystate) docs to learn more about the `disabled` state. diff --git a/website/docs/14.x/docs/api.md b/website/docs/14.x/docs/api.md index 74a342922..6da9af8e7 100644 --- a/website/docs/14.x/docs/api.md +++ b/website/docs/14.x/docs/api.md @@ -18,5 +18,5 @@ React Native Testing Library consists of following APIs: - [`renderHook` function](/docs/api/misc/render-hook) - render hooks for testing - [Async utils](/docs/api/misc/async): `findBy*` queries, `waitFor`, `waitForElementToBeRemoved` - [Configuration](/docs/api/misc/config): `configure`, `resetToDefaults` - - [Accessibility](/docs/api/misc/accessibility): `isHiddenFromAccessibility` + - [Accessibility](/docs/api/misc/accessibility): accessible name, `isHiddenFromAccessibility` - [Other](/docs/api/misc/other): `within`, `act`, `cleanup` diff --git a/website/docs/14.x/docs/api/jest-matchers.mdx b/website/docs/14.x/docs/api/jest-matchers.mdx index 54c9465de..a46090781 100644 --- a/website/docs/14.x/docs/api/jest-matchers.mdx +++ b/website/docs/14.x/docs/api/jest-matchers.mdx @@ -179,11 +179,9 @@ expect(element).toHaveAccessibleName( ) ``` -Checks if an element has the specified accessible name. Accepts `string` or `RegExp`, with optional [text match options](/docs/api/queries#text-match-options) like `exact` and `normalizer`. +Checks if an element has the specified [accessible name](/docs/api/misc/accessibility#accessible-name). Accepts `string` or `RegExp`, with optional [text match options](/docs/api/queries#text-match-options) like `exact` and `normalizer`. -The accessible name comes from `aria-labelledby`, `accessibilityLabelledBy`, `aria-label`, and `accessibilityLabel` props. For `Image` elements, the `alt` prop is also used. If none are present, the element's text content is used. - -When `accessibilityLabelledBy` references multiple elements with an array, their text content is joined with spaces in the referenced order and matched as a single accessible name. `aria-labelledby` follows React Native's single `nativeID` value behavior. +See [Accessible name](/docs/api/misc/accessibility#accessible-name) for how the accessible name is derived from an element's label props and text content. Without a `name` parameter (or with `undefined`), it only checks whether the element has any accessible name. diff --git a/website/docs/14.x/docs/api/misc/accessibility.mdx b/website/docs/14.x/docs/api/misc/accessibility.mdx index 187d60dd3..65dea6d88 100644 --- a/website/docs/14.x/docs/api/misc/accessibility.mdx +++ b/website/docs/14.x/docs/api/misc/accessibility.mdx @@ -1,5 +1,56 @@ # Accessibility +## Accessible name {#accessible-name} + +The **accessible name** is the text that assistive technologies (like screen readers) announce for an element. It answers the question: _"what would a screen reader call this element?"_. For instance, a button showing a trash icon might have the accessible name `"Delete"`, so a screen reader user knows what it does. + +Testing Library uses the accessible name in the [`*ByRole`](/docs/api/queries#by-role) queries `name` option and in the [`toHaveAccessibleName()`](/docs/api/jest-matchers#tohaveaccessiblename) matcher. Combining a role with an accessible name is a **semantic query**: it finds an element by what it is (`button`) and what it is called (`"Delete"`), rather than by its implementation details. This matches how users experience your UI. + +### How the accessible name is computed {#how-it-is-computed} + +The accessible name is the **first** of these sources to produce a non-empty value. The sources are ordered from highest to lowest importance. An explicit accessibility label that the developer assigned always takes precedence, and the element's own text content is only used when no such label is present. + +1. **`aria-labelledby` / `accessibilityLabelledBy`**: the [`nativeID`](https://reactnative.dev/docs/view#nativeid) (or array of IDs) of other elements, whose text content is joined with spaces in the referenced order. +2. **`aria-label` / `accessibilityLabel`**: an explicit label string on the element. +3. **`alt`** (`Image` only): the image's alternative text. +4. **`placeholder`** (`TextInput` only). +5. **Text content**: the element's own text, collected recursively from its children (see [Text content](#text-content) below). This is the fallback when none of the label sources above are set. + +### Text content {#text-content} + +When falling back to text content, child text is joined as follows: + +- Adjacent inline text (directly inside `Text` elements) is concatenated **without** a separator, matching how it renders on screen. +- Text from separate, non-inline elements, such as sibling `View`s, is joined with a **single space**. + +For example: + +```jsx +render( + + Hello + World + , +); +// Accessible name: "Hello World" +``` + +### Examples {#accessible-name-examples} + +```jsx +// Explicit label wins over text content + + X + +// Accessible name: "Close dialog" + +// Text content is used when no explicit label is set + + Submit + +// Accessible name: "Submit" +``` + ## `isHiddenFromAccessibility` ```ts diff --git a/website/docs/14.x/docs/api/queries.mdx b/website/docs/14.x/docs/api/queries.mdx index ccf5075df..c9e50977a 100644 --- a/website/docs/14.x/docs/api/queries.mdx +++ b/website/docs/14.x/docs/api/queries.mdx @@ -192,7 +192,7 @@ const element3 = screen.getByRole('button', { name: 'Hello', disabled: true }); #### Options {#by-role-options} -- `name`: Finds an element with given `role`/`accessibilityRole` and an accessible name (= accessability label or text content). +- `name`: Finds an element with given `role`/`accessibilityRole` and a matching [accessible name](/docs/api/misc/accessibility#accessible-name). The accessible name is the text a screen reader would announce for the element, derived from its label props or text content. See [Accessible name](/docs/api/misc/accessibility#accessible-name) for the details. - `disabled`: You can filter elements by their disabled state (coming either from `aria-disabled` prop or `accessbilityState.disabled` prop). The possible values are `true` or `false`. Querying `disabled: false` will also match elements with `disabled: undefined` (see the [wiki](https://github.com/callstack/react-native-testing-library/wiki/Accessibility:-State) for more details). - See [React Native's accessibilityState](https://reactnative.dev/docs/accessibility#accessibilitystate) docs to learn more about the `disabled` state.