Skip to content

fix(ui): label the full UI's controls for screen readers and test tools - #975

Merged
dannyhw merged 4 commits into
storybookjs:nextfrom
officialasishkumar:fix/ui-accessibility-labels
Nov 14, 2026
Merged

dannyhw merged 4 commits into
storybookjs:nextfrom
officialasishkumar:fix/ui-accessibility-labels

Conversation

@officialasishkumar

Copy link
Copy Markdown
Contributor

Issue: #153

What I did

Most of the full on-device UI's icon-only controls had no accessible name. VoiceOver and TalkBack read them as unlabelled buttons, and UI automation tools that find elements by accessibility label, like Appium (the use case in #153), couldn't target them. The lite UI already labels the same controls, so this gives @storybook/react-native-ui the same names and roles. The strings are the lite UI's, so selectors work in both UIs.

  • Layout: the desktop sidebar toggle ("Close sidebar" / "Open sidebar"), the desktop "Open addons panel" button, the mobile "Open story list" button, and the fullscreen button. The fullscreen button's label says what pressing it does ("Enter fullscreen" / "Exit fullscreen").
  • Search: the clear button ("Clear search"), each search result (its name and path, e.g. "Child B2, Group 1"), and the "Clear recently opened" button. The search field is named "Find components", the name web Storybook gives it.
  • Story tree: root, group, component and story rows are exposed as buttons, and the selected story row is marked as selected, so a screen reader tells you which story is open.
  • Logo: a brand image or title that links to brand.url is exposed as a link named after brand.title.
  • Expand all label (both UIs): the button on each root was labelled "Expand" when the root was fully expanded, where pressing it collapses everything, and "Collapse" when pressing it expands. It now says "Collapse all" / "Expand all" by what it does, matching web Storybook's sidebar. This is the only change in react-native-ui-lite.

No visual changes.

Tests: packages/react-native-ui/src/accessibility.test.tsx renders the layout and queries it by role and name, the way assistive tech and test tools see it. It covers mobile and desktop widths, the search flow, the expand all label and the logo. All 8 tests fail without the source changes. I put them in a new file instead of a Layout.test.tsx so they don't conflict with #968.

Changeset: patch for @storybook/react-native-ui and @storybook/react-native-ui-lite.

How to test

pnpm build
cd packages/react-native-ui && pnpm test

I ran the react-native-ui jest suite (3 suites, 14 tests), check:types for react-native-ui and react-native-ui-lite, and ESLint and Prettier on the changed files.

On device, run pnpm example with the full UI and turn on VoiceOver or TalkBack. The bottom bar's menu button reads "Open story list", the fullscreen button reads "Enter fullscreen" and then "Exit fullscreen", and story rows read as buttons, with the open story marked as selected. Appium can now select these controls by accessibility id.

  • Does this need a new example in examples/expo-example? No
  • Does this need an update to the documentation? No

The full on-device UI exposed most of its icon-only controls without an
accessible name, so VoiceOver and TalkBack announced them as unlabelled
buttons and UI automation tools that select elements by accessibility
label, such as Appium, could not find them. The lite UI already labels
the same controls.

Give the full UI the same names and roles as the lite UI:

- the desktop sidebar toggle ("Close sidebar" / "Open sidebar"), the
  desktop "Open addons panel" button, and the mobile story list button
  ("Open story list")
- the fullscreen button, labelled by what pressing it does ("Enter
  fullscreen" / "Exit fullscreen")
- the search clear button ("Clear search"), each search result (its
  name and path), and the "Clear recently opened" button
- a brand logo or title that links to `brand.url`, as a link
- the story tree's root, group, component and story rows as buttons

On top of what the lite UI has, the search field gets the name web
Storybook gives it ("Find components") and the selected story row is
marked as selected.

The "expand all" button on each root was labelled "Expand" when the
root was fully expanded and pressing it would collapse everything, and
"Collapse" when pressing it would expand. Label it "Collapse all" /
"Expand all" by what it does, as web Storybook does, in both UIs.

The tests render the layout and query it by role and name, the way
assistive tech and test tools see it, on mobile and desktop widths.

Refs storybookjs#153
@changeset-bot

changeset-bot Bot commented Nov 14, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 5943116

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 9 packages
Name Type
@storybook/react-native-ui Patch
@storybook/react-native-ui-lite Patch
@storybook/addon-ondevice-actions Patch
@storybook/addon-ondevice-backgrounds Patch
@storybook/addon-ondevice-controls Patch
@storybook/addon-ondevice-notes Patch
@storybook/react-native-theming Patch
@storybook/react-native-ui-common Patch
@storybook/react-native Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@chatgpt-codex-connector

Copy link
Copy Markdown
Codex Review Summary: ❌ Failed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ❌ Failed 2026-11-14T16:12:45.113187Z
We couldn’t complete this review. Comment @codex review to try again.
7b21baa PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@dannyhw

dannyhw commented Nov 14, 2026

Copy link
Copy Markdown
Member

just want to call out that most actions in the app can be controlled via rest/websocket requests or via the mcp, though no issue with adding labels

dannyhw and others added 3 commits November 14, 2026 18:12
… lite search field

The story list button's "Open story list" label replaces its visible
story path on iOS, so expose the open story as the button's accessibility
value in both UIs. Label the lite UI's search input "Find components" to
match the full UI.
On Android, React Native appends accessibilityValue.text to the content
description, so the button was exposed as "Open story list, <story>" and
an exact "Open story list" selector stopped matching. Android already
exposes the button's visible text as a child node, so the value is only
needed on iOS, where the label replaces the text.
@dannyhw
dannyhw merged commit 503529a into storybookjs:next Nov 14, 2026
1 check passed
@dannyhw

dannyhw commented Nov 14, 2026

Copy link
Copy Markdown
Member

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants