You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Chip: accessibilityState passed by caller is discarded; aria-checked is never forwarded to the real rendered node #5146
Chip destructures selected/disabled/etc. and computes its own accessibilityState={{ selected, disabled }} internally, but any accessibilityState (or aria-checked) a caller passes in falls into ...rest and is spread onto the outer, non-interactive Surface — never reaching the interactive TouchableRipple/Pressable node.
This is a real accessibility gap on web: react-native-web does not derive aria-* attributes from a native accessibilityState object at all (confirmed via react-native-web's forwardedProps/index.js allowlist, which only forwards a literal aria-checked prop straight to the DOM). So even though Chip's own internally-computed accessibilityState happens to reach the real Pressable on native (where RN's Pressable merges accessibilityState.checked itself), there is no equivalent path on web, and Chip never sets aria-checked itself.
Net effect: a Chip rendered as part of a custom radio/checkbox group (e.g. a chip-based single/multi-select control) reports checked: false in the web accessibility tree for every option, including the selected one — a screen reader user on web cannot tell which option is selected.
Reproduction
Render a Chip with selected={true} inside PaperProvider, on web (react-native-web).
Inspect the rendered DOM / accessibility tree.
No aria-checked attribute is present anywhere in the output.
Expected behavior
Chip should forward a literal aria-checked prop (distinct from accessibilityState) through to the real interactive node it renders (TouchableRipple → Pressable), so consumers building a custom selectable-chip group can make selection state screen-reader-visible on web.
Additional context
Verified the in-flight 6.0.0 refactor (commit 466d9c608d2cb3dead7831b64c925f4523419b0e, PR refactor: migrate accessibility props to aria props #5005, "refactor: migrate accessibility props to aria props") does not fix this: it adds role/aria-label/aria-selected/aria-disabled forwarding to TouchableRipple, but Chip's own vocabulary there is selected/aria-selected, not checked/aria-checked — an unrecognized aria-checked is still spread via ...rest onto the non-interactive Surface in that version too.
react-native-paper version: 5.15.3 (latest stable at time of filing).
We've applied a local patch-package patch forwarding aria-checked through Chip → TouchableRipple → Pressable as a workaround; happy to share the patch/diff if useful upstream.
I checked the current main path: Chip.tsx sends ...rest to the outer Surface, while the interactive TouchableRipple only receives aria-label, role, aria-selected, and aria-disabled (lines 301–304). TouchableRipple forwards its props to Pressable, so a narrow fix can pull aria-checked out of rest and pass it there. A focused web regression test could render role="checkbox" with aria-checked true and false, then assert the attribute is on the actual interactive DOM node and absent from the outer Surface; that checks both placement and value.
Activity
dave-otf commentedon Oct 27, 2026
I checked the current main path: Chip.tsx sends
...restto the outerSurface, while the interactiveTouchableRippleonly receivesaria-label,role,aria-selected, andaria-disabled(lines 301–304). TouchableRipple forwards its props toPressable, so a narrow fix can pullaria-checkedout ofrestand pass it there. A focused web regression test could renderrole="checkbox"witharia-checkedtrue and false, then assert the attribute is on the actual interactive DOM node and absent from the outerSurface; that checks both placement and value.