Skip to content

Commit e3437cb

Browse files
faciledictumeta-codesync[bot]
authored andcommitted
fix(View): map aria-modal to accessibilityViewIsModal (#59328)
Summary: The `View` docs list `aria-modal` as an iOS prop that "has precedence over the `accessibilityViewIsModal` prop". `View` does not map it, though: `View.js` converts `aria-label`, `aria-live`, `aria-hidden` and the other `aria-*` props to their `accessibility*` forms, but `aria-modal` is passed through unchanged, and the native side only reads `accessibilityViewIsModal`. As a result `<View aria-modal>` does nothing, and VoiceOver can still reach the views behind a custom dialog. When `aria-modal` was added in #34506, it was mapped in `Pressable` and the `Touchable*` components and added to `ViewPropTypes`, but `View.js` itself was not changed, so the prop is typed and documented on `View` but has no effect there. This change maps `aria-modal` to `accessibilityViewIsModal` in `View`, with `aria-modal` taking precedence, as documented. ## Changelog: [IOS] [FIXED] - `aria-modal` on `View` now sets `accessibilityViewIsModal` Pull Request resolved: #59328 Test Plan: Checked on an iPhone (iOS 27) with React Native 0.88.0 (Expo SDK 58, development build), VoiceOver on. A screen with three background buttons and a custom overlay that is their sibling: ```tsx import { useState } from 'react'; import { Pressable, Text, View } from 'react-native'; export default function App() { const [open, setOpen] = useState(false); return ( <View style={{ flex: 1 }}> <View style={{ flex: 1, padding: 48, gap: 16 }}> {['One', 'Two', 'Three'].map((title) => ( <Pressable key={title} role="button"> <Text>Background item {title}</Text> </Pressable> ))} <Pressable role="button" onPress={() => setOpen(true)}> <Text>Open the dialog</Text> </Pressable> </View> {open && ( <View aria-modal style={{ position: 'absolute', inset: 0, justifyContent: 'center', padding: 32, backgroundColor: 'rgba(0,0,0,0.4)', }} > <View style={{ backgroundColor: 'white', padding: 24, gap: 16 }}> <Text role="heading">Dialog</Text> <Pressable role="button" onPress={() => setOpen(false)}> <Text>Close</Text> </Pressable> </View> </View> )} </View> ); } ``` Before: with the dialog open, swiping right goes past "Close" to the "Background item" buttons, and touching where they are focuses them. Replacing `aria-modal` with `accessibilityViewIsModal` keeps focus inside the dialog. After: `aria-modal` behaves the same as `accessibilityViewIsModal`. Reviewed By: andrewdacenko Differential Revision: D126904378 Pulled By: javache fbshipit-source-id: 698cceaa5ad45c68c6fd9eb7fa002da4901a7aa1
1 parent be7180b commit e3437cb

1 file changed

Lines changed: 5 additions & 0 deletions

File tree

  • packages/react-native/Libraries/Components/View

‎packages/react-native/Libraries/Components/View/View.js‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ component View(ref?: React.RefSetter<ViewInstance>, ...props: ViewProps) {
5050
'aria-label': ariaLabel,
5151
'aria-labelledby': ariaLabelledBy,
5252
'aria-live': ariaLive,
53+
'aria-modal': ariaModal,
5354
'aria-selected': ariaSelected,
5455
'aria-valuemax': ariaValueMax,
5556
'aria-valuemin': ariaValueMin,
@@ -76,6 +77,10 @@ component View(ref?: React.RefSetter<ViewInstance>, ...props: ViewProps) {
7677
ariaLive === 'off' ? 'none' : ariaLive;
7778
}
7879

80+
if (ariaModal !== undefined) {
81+
resolvedProps.accessibilityViewIsModal = ariaModal;
82+
}
83+
7984
if (ariaHidden !== undefined) {
8085
resolvedProps.accessibilityElementsHidden = ariaHidden;
8186
if (ariaHidden === true) {

0 commit comments

Comments
 (0)