diff --git a/Libraries/Components/Pressable/Pressable.js b/Libraries/Components/Pressable/Pressable.js index 081a960e4a4ddb..9c41c9948b0bf8 100644 --- a/Libraries/Components/Pressable/Pressable.js +++ b/Libraries/Components/Pressable/Pressable.js @@ -68,6 +68,7 @@ type Props = $ReadOnly<{| * this accessibility element are hidden. */ 'aria-hidden'?: ?boolean, + 'aria-live'?: ?('polite' | 'assertive' | 'off'), focusable?: ?boolean, importantForAccessibility?: ?('auto' | 'yes' | 'no' | 'no-hide-descendants'), onAccessibilityAction?: ?(event: AccessibilityActionEvent) => mixed, @@ -190,10 +191,11 @@ type Props = $ReadOnly<{| * LTI update could not be added via codemod */ function Pressable(props: Props, forwardedRef): React.Node { const { + accessible, accessibilityState, + 'aria-live': ariaLive, android_disableSound, android_ripple, - accessible, 'aria-busy': ariaBusy, 'aria-checked': ariaChecked, 'aria-disabled': ariaDisabled, @@ -238,10 +240,14 @@ function Pressable(props: Props, forwardedRef): React.Node { _accessibilityState = disabled != null ? {..._accessibilityState, disabled} : _accessibilityState; + const accessibilityLiveRegion = + ariaLive === 'off' ? 'none' : ariaLive ?? props.accessibilityLiveRegion; + const restPropsWithDefaults: React.ElementConfig = { ...restProps, ...android_rippleConfig?.viewProps, accessible: accessible !== false, + accessibilityLiveRegion, accessibilityState: _accessibilityState, focusable: focusable !== false, hitSlop, diff --git a/Libraries/Components/Touchable/TouchableBounce.js b/Libraries/Components/Touchable/TouchableBounce.js index a5f999afe5dc62..3f611f25c03e3a 100644 --- a/Libraries/Components/Touchable/TouchableBounce.js +++ b/Libraries/Components/Touchable/TouchableBounce.js @@ -130,7 +130,10 @@ class TouchableBounce extends React.Component { // adopting `Pressability`, so preserve that behavior. const {onBlur, onFocus, ...eventHandlersWithoutBlurAndFocus} = this.state.pressability.getEventHandlers(); - + const accessibilityLiveRegion = + this.props['aria-live'] === 'off' + ? 'none' + : this.props['aria-live'] ?? this.props.accessibilityLiveRegion; const _accessibilityState = { busy: this.props['aria-busy'] ?? this.props.accessibilityState?.busy, checked: @@ -155,12 +158,12 @@ class TouchableBounce extends React.Component { accessibilityActions={this.props.accessibilityActions} onAccessibilityAction={this.props.onAccessibilityAction} accessibilityValue={this.props.accessibilityValue} + accessibilityLiveRegion={accessibilityLiveRegion} importantForAccessibility={ this.props['aria-hidden'] === true ? 'no-hide-descendants' : this.props.importantForAccessibility } - accessibilityLiveRegion={this.props.accessibilityLiveRegion} accessibilityViewIsModal={this.props.accessibilityViewIsModal} accessibilityElementsHidden={ this.props['aria-hidden'] ?? this.props.accessibilityElementsHidden diff --git a/Libraries/Components/Touchable/TouchableHighlight.js b/Libraries/Components/Touchable/TouchableHighlight.js index 9bda74f946a4ea..7729d067daef03 100644 --- a/Libraries/Components/Touchable/TouchableHighlight.js +++ b/Libraries/Components/Touchable/TouchableHighlight.js @@ -290,7 +290,10 @@ class TouchableHighlight extends React.Component { disabled: this.props.disabled, } : this.props.accessibilityState; - + const accessibilityLiveRegion = + this.props['aria-live'] === 'off' + ? 'none' + : this.props['aria-live'] ?? this.props.accessibilityLiveRegion; return ( { ? 'no-hide-descendants' : this.props.importantForAccessibility } - accessibilityLiveRegion={this.props.accessibilityLiveRegion} + accessibilityLiveRegion={accessibilityLiveRegion} accessibilityViewIsModal={this.props.accessibilityViewIsModal} accessibilityElementsHidden={ this.props['aria-hidden'] ?? this.props.accessibilityElementsHidden diff --git a/Libraries/Components/Touchable/TouchableNativeFeedback.js b/Libraries/Components/Touchable/TouchableNativeFeedback.js index 7f305fd70869a9..265c8489041cf0 100644 --- a/Libraries/Components/Touchable/TouchableNativeFeedback.js +++ b/Libraries/Components/Touchable/TouchableNativeFeedback.js @@ -273,6 +273,11 @@ class TouchableNativeFeedback extends React.Component { } : _accessibilityState; + const accessibilityLiveRegion = + this.props['aria-live'] === 'off' + ? 'none' + : this.props['aria-live'] ?? this.props.accessibilityLiveRegion; + return React.cloneElement( element, { @@ -296,7 +301,7 @@ class TouchableNativeFeedback extends React.Component { this.props['aria-hidden'] === true ? 'no-hide-descendants' : this.props.importantForAccessibility, - accessibilityLiveRegion: this.props.accessibilityLiveRegion, + accessibilityLiveRegion: accessibilityLiveRegion, accessibilityViewIsModal: this.props.accessibilityViewIsModal, accessibilityElementsHidden: this.props['aria-hidden'] ?? this.props.accessibilityElementsHidden, diff --git a/Libraries/Components/Touchable/TouchableOpacity.js b/Libraries/Components/Touchable/TouchableOpacity.js index 1d4f392cbde3c2..016f65bd8a5dde 100644 --- a/Libraries/Components/Touchable/TouchableOpacity.js +++ b/Libraries/Components/Touchable/TouchableOpacity.js @@ -235,6 +235,11 @@ class TouchableOpacity extends React.Component { } : _accessibilityState; + const accessibilityLiveRegion = + this.props['aria-live'] === 'off' + ? 'none' + : this.props['aria-live'] ?? this.props.accessibilityLiveRegion; + return ( { ? 'no-hide-descendants' : this.props.importantForAccessibility } - accessibilityLiveRegion={this.props.accessibilityLiveRegion} + accessibilityLiveRegion={accessibilityLiveRegion} accessibilityViewIsModal={this.props.accessibilityViewIsModal} accessibilityElementsHidden={ this.props['aria-hidden'] ?? this.props.accessibilityElementsHidden diff --git a/Libraries/Components/Touchable/TouchableWithoutFeedback.js b/Libraries/Components/Touchable/TouchableWithoutFeedback.js index bb46921c8c9c75..ab5a019bc9173f 100755 --- a/Libraries/Components/Touchable/TouchableWithoutFeedback.js +++ b/Libraries/Components/Touchable/TouchableWithoutFeedback.js @@ -53,6 +53,7 @@ type Props = $ReadOnly<{| 'aria-expanded'?: ?boolean, 'aria-selected'?: ?boolean, 'aria-hidden'?: ?boolean, + 'aria-live'?: ?('polite' | 'assertive' | 'off'), children?: ?React.Node, delayLongPress?: ?number, delayPressIn?: ?number, @@ -82,6 +83,7 @@ type State = $ReadOnly<{| const PASSTHROUGH_PROPS = [ 'accessibilityActions', + 'accessibilityElementsHidden', 'accessibilityHint', 'accessibilityLanguage', 'accessibilityIgnoresInvertColors', @@ -91,6 +93,7 @@ const PASSTHROUGH_PROPS = [ 'accessibilityValue', 'accessibilityViewIsModal', 'hitSlop', + 'importantForAccessibility', 'nativeID', 'onAccessibilityAction', 'onBlur', @@ -107,6 +110,8 @@ class TouchableWithoutFeedback extends React.Component { render(): React.Node { const element = React.Children.only(this.props.children); const children = [element.props.children]; + const ariaLive = this.props['aria-live']; + if (__DEV__) { if (element.type === View) { children.push( @@ -151,6 +156,10 @@ class TouchableWithoutFeedback extends React.Component { this.props['aria-hidden'] === true ? 'no-hide-descendants' : this.props.importantForAccessibility, + accessibilityLiveRegion: + ariaLive === 'off' + ? 'none' + : ariaLive ?? this.props.accessibilityLiveRegion, }; for (const prop of PASSTHROUGH_PROPS) { if (this.props[prop] !== undefined) { diff --git a/Libraries/Components/View/View.js b/Libraries/Components/View/View.js index 932eeb121e64ec..9fbab16d0b8130 100644 --- a/Libraries/Components/View/View.js +++ b/Libraries/Components/View/View.js @@ -31,6 +31,8 @@ const View: React.AbstractComponent< ( { accessibilityElementsHidden, + accessibilityLiveRegion, + 'aria-live': ariaLive, accessibilityRole, 'aria-hidden': ariaHidden, focusable, @@ -135,6 +137,9 @@ const View: React.AbstractComponent< return ( = 19 only. + * + * @platform android + * + * See https://reactnative.dev/docs/view#accessibilityliveregion + */ + 'aria-live'?: ?('polite' | 'assertive' | 'off'), + /** * Controls how view is important for accessibility which is if it * fires accessibility events and if it is reported to accessibility services