Skip to content

Native ARIA Roles: iOS Paper + Fabric - #37309

Closed
NickGerleman wants to merge 1 commit into
react:mainfrom
NickGerleman:export-D45432530
Closed

NickGerleman wants to merge 1 commit into
react:mainfrom
NickGerleman:export-D45432530

Conversation

@NickGerleman

Copy link
Copy Markdown
Contributor

Summary:

Stack

ARIA roles in React Native are implemented on top of accessibilityRole. This is lossy because there are many more ARIA roles than accessibilityRole. This is especially true for RN on desktop where accessibilityRole was designed around accessibility APIs only available on mobile.

This series of changes aims to change this implementation to instead pass the ARIA role to native, alongside any existing accessibilityRole. This gives the platform more control in exactly how to map an ARIA role to native behavior.

As an example, this would allow mapping any ARIA role to AutomationControlType on Windows without needing to fork to add new options to accessibilityRole.

It also allows greater implementation flexibility for other platforms down the line, but for now, iOS and Android behave the same as before (though with their implementation living in native).

Diff

This enables the role prop in iOS. ARIA role strings become convertible to UIAccessibilityTrait, which is the sink of most of the roles. We keep a list of traits derived from role vs accessibilityRole on the view, then inval and apply the result any time the prop for either is set.

Changelog: [Internal]

Differential Revision: D45432530

@facebook-github-bot facebook-github-bot added CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. p: Facebook Partner: Facebook Partner fb-exported labels May 8, 2023
@facebook-github-bot

Copy link
Copy Markdown
Contributor

This pull request was exported from Phabricator. Differential Revision: D45432530

@analysis-bot

analysis-bot commented May 8, 2023 •

Copy link
Copy Markdown
Platform Engine Arch Size (bytes) Diff
android hermes arm64-v8a 8,744,388 -354
android hermes armeabi-v7a 8,056,526 -56
android hermes x86 9,235,450 -251
android hermes x86_64 9,086,233 -281
android jsc arm64-v8a 9,307,099 -348
android jsc armeabi-v7a 8,496,608 -71
android jsc x86 9,369,073 -250
android jsc x86_64 9,623,974 -286

Base commit: d54f486
Branch: main

@facebook-github-bot

Copy link
Copy Markdown
Contributor

This pull request was exported from Phabricator. Differential Revision: D45432530

1 similar comment
@facebook-github-bot

Copy link
Copy Markdown
Contributor

This pull request was exported from Phabricator. Differential Revision: D45432530

@facebook-github-bot

Copy link
Copy Markdown
Contributor

This pull request was exported from Phabricator. Differential Revision: D45432530

@facebook-github-bot

Copy link
Copy Markdown
Contributor

This pull request was exported from Phabricator. Differential Revision: D45432530

@facebook-github-bot

Copy link
Copy Markdown
Contributor

This pull request was exported from Phabricator. Differential Revision: D45432530

1 similar comment
@facebook-github-bot

Copy link
Copy Markdown
Contributor

This pull request was exported from Phabricator. Differential Revision: D45432530

@facebook-github-bot

Copy link
Copy Markdown
Contributor

This pull request was exported from Phabricator. Differential Revision: D45432530

@facebook-github-bot

Copy link
Copy Markdown
Contributor

This pull request was exported from Phabricator. Differential Revision: D45432530

Summary:
Pull Request resolved: react#37309

### Stack

ARIA roles in React Native are implemented on top of accessibilityRole. This is lossy because there are many more ARIA roles than accessibilityRole. This is especially true for RN on desktop where accessibilityRole was designed around accessibility APIs only available on mobile.

This series of changes aims to change this implementation to instead pass the ARIA role to native, alongside any existing accessibilityRole. This gives the platform more control in exactly how to map an ARIA role to native behavior.

As an example, this would allow mapping any ARIA role to AutomationControlType on Windows without needing to fork to add new options to accessibilityRole.

It also allows greater implementation flexibility for other platforms down the line, but for now, iOS and Android behave the same as before (though with their implementation living in native).

### Diff

This enables the `role` prop in iOS. ARIA role strings become convertible to `UIAccessibilityTrait`, which is the sink of most of the roles. We keep a list of traits derived from `role` vs `accessibilityRole` on the view, then inval and apply the result any time the prop for either is set.

Changelog: [Internal]

Reviewed By: sammy-SC

Differential Revision: D45432530

fbshipit-source-id: 38d516d08b4a987ed9a274c88eb29df6538f76b8
@facebook-github-bot

Copy link
Copy Markdown
Contributor

This pull request was exported from Phabricator. Differential Revision: D45432530

@facebook-github-bot facebook-github-bot added the Merged This PR has been merged. label Jun 4, 2023
@facebook-github-bot

Copy link
Copy Markdown
Contributor

This pull request has been merged in 2d07d5f.

meta-codesync Bot pushed a commit that referenced this pull request Oct 26, 2026
Summary:
Hi, I'm a React Native developer. Thanks for the recent iOS accessibility work.

On iOS, `role="slider"` ends up with no accessibility traits, so VoiceOver doesn't treat the view as adjustable. `accessibilityRole="adjustable"` on the same view works. The traits come from `fromString(const std::string &, AccessibilityTraits &)` in `accessibilityPropsConversions.h`, which has an `"adjustable"` case but no `"slider"` case.

Before the ARIA roles moved to native in #37309, the JS mapping turned `role: 'slider'` into `accessibilityRole: 'adjustable'`, so this used to work. The native table maps `slider` to no trait instead. This adds `slider` to the `adjustable` case, the same way `img`/`image` and `heading`/`header` share a case. Android doesn't read `accessibilityTraits`, so only iOS changes.

It only touches `slider`. The other roles listed in #50123 stay as they are, since the comment above `RCTViewIsInteractiveAccessibilityElement` says some of them carry no trait on purpose. I also left the legacy `RCTViewManager.m` table alone, which maps `slider` to `UIAccessibilityTraitNone` as well. Happy to change that one too if it's still wanted.

Part of #50123.

## Changelog:

[IOS] [FIXED] - `role="slider"` now gets the adjustable accessibility trait, like `accessibilityRole="adjustable"`

Pull Request resolved: #59463

Test Plan:
RNTester on an iPhone 18 Pro simulator (iOS 27.0), with the Playground rendering:

```tsx
<View accessible role="slider" accessibilityLabel="Role slider" accessibilityValue={{min: 0, max: 10, now: 5}} />
<View accessible accessibilityRole="adjustable" accessibilityLabel="AccessibilityRole adjustable" accessibilityValue={{min: 0, max: 10, now: 5}} />
```

The simulator's accessibility tree for both views:

```
main     Role slider                   AXGroup       traits: none
         AccessibilityRole adjustable  AXAdjustable  traits: adjustable
this PR  Role slider                   AXAdjustable  traits: adjustable
         AccessibilityRole adjustable  AXAdjustable  traits: adjustable
```

- Added `derives_adjustable_trait_from_slider_role` to `AccessibilityPropsTest.cpp`, next to `derives_traits_from_role`. I couldn't run it, because I didn't find a way to run the ReactCommon gtests from the open-source checkout.
- `node scripts/clang-format.js --check` passes on both files.
- Not checked: the legacy architecture.

Reviewed By: christophpurrer

Differential Revision: D127482367

Pulled By: Abbondanzo

fbshipit-source-id: bd315b64e1492c92d7a2b20831bab2dd636d2360
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. fb-exported Merged This PR has been merged. p: Facebook Partner: Facebook Partner

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants