diff --git a/Libraries/Components/Pressable/Pressable.js b/Libraries/Components/Pressable/Pressable.js
index 9c41c9948b0bf8..7ad0c494e0155c 100644
--- a/Libraries/Components/Pressable/Pressable.js
+++ b/Libraries/Components/Pressable/Pressable.js
@@ -50,6 +50,10 @@ type Props = $ReadOnly<{|
accessibilityRole?: ?AccessibilityRole,
accessibilityState?: ?AccessibilityState,
accessibilityValue?: ?AccessibilityValue,
+ 'aria-valuemax'?: AccessibilityValue['max'],
+ 'aria-valuemin'?: AccessibilityValue['min'],
+ 'aria-valuenow'?: AccessibilityValue['now'],
+ 'aria-valuetext'?: AccessibilityValue['text'],
accessibilityViewIsModal?: ?boolean,
accessible?: ?boolean,
@@ -240,6 +244,13 @@ function Pressable(props: Props, forwardedRef): React.Node {
_accessibilityState =
disabled != null ? {..._accessibilityState, disabled} : _accessibilityState;
+ const accessibilityValue = {
+ max: props['aria-valuemax'] ?? props.accessibilityValue?.max,
+ min: props['aria-valuemin'] ?? props.accessibilityValue?.min,
+ now: props['aria-valuenow'] ?? props.accessibilityValue?.now,
+ text: props['aria-valuetext'] ?? props.accessibilityValue?.text,
+ };
+
const accessibilityLiveRegion =
ariaLive === 'off' ? 'none' : ariaLive ?? props.accessibilityLiveRegion;
@@ -250,6 +261,7 @@ function Pressable(props: Props, forwardedRef): React.Node {
accessibilityLiveRegion,
accessibilityState: _accessibilityState,
focusable: focusable !== false,
+ accessibilityValue,
hitSlop,
};
diff --git a/Libraries/Components/Pressable/__tests__/__snapshots__/Pressable-test.js.snap b/Libraries/Components/Pressable/__tests__/__snapshots__/Pressable-test.js.snap
index 4e03820efa8ea3..e348e02347e52b 100644
--- a/Libraries/Components/Pressable/__tests__/__snapshots__/Pressable-test.js.snap
+++ b/Libraries/Components/Pressable/__tests__/__snapshots__/Pressable-test.js.snap
@@ -11,6 +11,14 @@ exports[` should render as expected: should deep render when mocked
"selected": undefined,
}
}
+ accessibilityValue={
+ Object {
+ "max": undefined,
+ "min": undefined,
+ "now": undefined,
+ "text": undefined,
+ }
+ }
accessible={true}
collapsable={false}
focusable={true}
@@ -39,6 +47,14 @@ exports[` should render as expected: should deep render when not mo
"selected": undefined,
}
}
+ accessibilityValue={
+ Object {
+ "max": undefined,
+ "min": undefined,
+ "now": undefined,
+ "text": undefined,
+ }
+ }
accessible={true}
collapsable={false}
focusable={true}
@@ -79,6 +95,14 @@ exports[` should be disabled when disabled is true:
"selected": undefined,
}
}
+ accessibilityValue={
+ Object {
+ "max": undefined,
+ "min": undefined,
+ "now": undefined,
+ "text": undefined,
+ }
+ }
accessible={true}
collapsable={false}
focusable={true}
@@ -107,6 +131,14 @@ exports[` should be disabled when disabled is true:
"selected": undefined,
}
}
+ accessibilityValue={
+ Object {
+ "max": undefined,
+ "min": undefined,
+ "now": undefined,
+ "text": undefined,
+ }
+ }
accessible={true}
collapsable={false}
focusable={true}
@@ -151,6 +183,14 @@ exports[` should be disable
"selected": undefined,
}
}
+ accessibilityValue={
+ Object {
+ "max": undefined,
+ "min": undefined,
+ "now": undefined,
+ "text": undefined,
+ }
+ }
accessible={true}
collapsable={false}
focusable={true}
@@ -179,6 +219,14 @@ exports[` should be disable
"selected": undefined,
}
}
+ accessibilityValue={
+ Object {
+ "max": undefined,
+ "min": undefined,
+ "now": undefined,
+ "text": undefined,
+ }
+ }
accessible={true}
collapsable={false}
focusable={true}
@@ -225,6 +273,14 @@ exports[` shou
"selected": undefined,
}
}
+ accessibilityValue={
+ Object {
+ "max": undefined,
+ "min": undefined,
+ "now": undefined,
+ "text": undefined,
+ }
+ }
accessible={true}
collapsable={false}
focusable={true}
@@ -253,6 +309,14 @@ exports[` shou
"selected": undefined,
}
}
+ accessibilityValue={
+ Object {
+ "max": undefined,
+ "min": undefined,
+ "now": undefined,
+ "text": undefined,
+ }
+ }
accessible={true}
collapsable={false}
focusable={true}
@@ -307,6 +371,14 @@ exports[` sh
"selected": undefined,
}
}
+ accessibilityValue={
+ Object {
+ "max": undefined,
+ "min": undefined,
+ "now": undefined,
+ "text": undefined,
+ }
+ }
accessible={true}
collapsable={false}
focusable={true}
@@ -335,6 +407,14 @@ exports[` sh
"selected": undefined,
}
}
+ accessibilityValue={
+ Object {
+ "max": undefined,
+ "min": undefined,
+ "now": undefined,
+ "text": undefined,
+ }
+ }
accessible={true}
collapsable={false}
focusable={true}
diff --git a/Libraries/Components/Touchable/TouchableBounce.js b/Libraries/Components/Touchable/TouchableBounce.js
index 3f611f25c03e3a..8b05a64ffd896b 100644
--- a/Libraries/Components/Touchable/TouchableBounce.js
+++ b/Libraries/Components/Touchable/TouchableBounce.js
@@ -146,6 +146,13 @@ class TouchableBounce extends React.Component {
this.props['aria-selected'] ?? this.props.accessibilityState?.selected,
};
+ const accessibilityValue = {
+ max: this.props['aria-valuemax'] ?? this.props.accessibilityValue?.max,
+ min: this.props['aria-valuemin'] ?? this.props.accessibilityValue?.min,
+ now: this.props['aria-valuenow'] ?? this.props.accessibilityValue?.now,
+ text: this.props['aria-valuetext'] ?? this.props.accessibilityValue?.text,
+ };
+
return (
{
accessibilityState={_accessibilityState}
accessibilityActions={this.props.accessibilityActions}
onAccessibilityAction={this.props.onAccessibilityAction}
- accessibilityValue={this.props.accessibilityValue}
+ accessibilityValue={accessibilityValue}
accessibilityLiveRegion={accessibilityLiveRegion}
importantForAccessibility={
this.props['aria-hidden'] === true
diff --git a/Libraries/Components/Touchable/TouchableHighlight.js b/Libraries/Components/Touchable/TouchableHighlight.js
index 7729d067daef03..053824e0edd790 100644
--- a/Libraries/Components/Touchable/TouchableHighlight.js
+++ b/Libraries/Components/Touchable/TouchableHighlight.js
@@ -290,10 +290,19 @@ class TouchableHighlight extends React.Component {
disabled: this.props.disabled,
}
: this.props.accessibilityState;
+
+ const accessibilityValue = {
+ max: this.props['aria-valuemax'] ?? this.props.accessibilityValue?.max,
+ min: this.props['aria-valuemin'] ?? this.props.accessibilityValue?.min,
+ now: this.props['aria-valuenow'] ?? this.props.accessibilityValue?.now,
+ text: this.props['aria-valuetext'] ?? this.props.accessibilityValue?.text,
+ };
+
const accessibilityLiveRegion =
this.props['aria-live'] === 'off'
? 'none'
: this.props['aria-live'] ?? this.props.accessibilityLiveRegion;
+
return (
{
accessibilityLanguage={this.props.accessibilityLanguage}
accessibilityRole={this.props.accessibilityRole}
accessibilityState={accessibilityState}
- accessibilityValue={this.props.accessibilityValue}
+ accessibilityValue={accessibilityValue}
accessibilityActions={this.props.accessibilityActions}
onAccessibilityAction={this.props.onAccessibilityAction}
importantForAccessibility={
diff --git a/Libraries/Components/Touchable/TouchableNativeFeedback.js b/Libraries/Components/Touchable/TouchableNativeFeedback.js
index 21a4061e13ede2..ac5b793ac85295 100644
--- a/Libraries/Components/Touchable/TouchableNativeFeedback.js
+++ b/Libraries/Components/Touchable/TouchableNativeFeedback.js
@@ -273,6 +273,13 @@ class TouchableNativeFeedback extends React.Component {
}
: _accessibilityState;
+ const accessibilityValue = {
+ max: this.props['aria-valuemax'] ?? this.props.accessibilityValue?.max,
+ min: this.props['aria-valuemin'] ?? this.props.accessibilityValue?.min,
+ now: this.props['aria-valuenow'] ?? this.props.accessibilityValue?.now,
+ text: this.props['aria-valuetext'] ?? this.props.accessibilityValue?.text,
+ };
+
const accessibilityLiveRegion =
this.props['aria-live'] === 'off'
? 'none'
@@ -296,7 +303,7 @@ class TouchableNativeFeedback extends React.Component {
accessibilityState: _accessibilityState,
accessibilityActions: this.props.accessibilityActions,
onAccessibilityAction: this.props.onAccessibilityAction,
- accessibilityValue: this.props.accessibilityValue,
+ accessibilityValue: accessibilityValue,
importantForAccessibility:
this.props['aria-hidden'] === true
? 'no-hide-descendants'
diff --git a/Libraries/Components/Touchable/TouchableOpacity.js b/Libraries/Components/Touchable/TouchableOpacity.js
index 016f65bd8a5dde..7e6537d0c230b2 100644
--- a/Libraries/Components/Touchable/TouchableOpacity.js
+++ b/Libraries/Components/Touchable/TouchableOpacity.js
@@ -235,6 +235,13 @@ class TouchableOpacity extends React.Component {
}
: _accessibilityState;
+ const accessibilityValue = {
+ max: this.props['aria-valuemax'] ?? this.props.accessibilityValue?.max,
+ min: this.props['aria-valuemin'] ?? this.props.accessibilityValue?.min,
+ now: this.props['aria-valuenow'] ?? this.props.accessibilityValue?.now,
+ text: this.props['aria-valuetext'] ?? this.props.accessibilityValue?.text,
+ };
+
const accessibilityLiveRegion =
this.props['aria-live'] === 'off'
? 'none'
@@ -250,7 +257,7 @@ class TouchableOpacity extends React.Component {
accessibilityState={_accessibilityState}
accessibilityActions={this.props.accessibilityActions}
onAccessibilityAction={this.props.onAccessibilityAction}
- accessibilityValue={this.props.accessibilityValue}
+ accessibilityValue={accessibilityValue}
importantForAccessibility={
this.props['aria-hidden'] === true
? 'no-hide-descendants'
diff --git a/Libraries/Components/Touchable/TouchableWithoutFeedback.js b/Libraries/Components/Touchable/TouchableWithoutFeedback.js
index ab5a019bc9173f..ab2d844253b717 100755
--- a/Libraries/Components/Touchable/TouchableWithoutFeedback.js
+++ b/Libraries/Components/Touchable/TouchableWithoutFeedback.js
@@ -40,6 +40,10 @@ type Props = $ReadOnly<{|
accessibilityRole?: ?AccessibilityRole,
accessibilityState?: ?AccessibilityState,
accessibilityValue?: ?AccessibilityValue,
+ 'aria-valuemax'?: AccessibilityValue['max'],
+ 'aria-valuemin'?: AccessibilityValue['min'],
+ 'aria-valuenow'?: AccessibilityValue['now'],
+ 'aria-valuetext'?: AccessibilityValue['text'],
accessibilityViewIsModal?: ?boolean,
accessible?: ?boolean,
/**
@@ -91,6 +95,10 @@ const PASSTHROUGH_PROPS = [
'accessibilityLiveRegion',
'accessibilityRole',
'accessibilityValue',
+ 'aria-valuemax',
+ 'aria-valuemin',
+ 'aria-valuenow',
+ 'aria-valuetext',
'accessibilityViewIsModal',
'hitSlop',
'importantForAccessibility',
diff --git a/Libraries/Components/Touchable/__tests__/__snapshots__/TouchableHighlight-test.js.snap b/Libraries/Components/Touchable/__tests__/__snapshots__/TouchableHighlight-test.js.snap
index 70eaabe704a1f0..35c845e97493fc 100644
--- a/Libraries/Components/Touchable/__tests__/__snapshots__/TouchableHighlight-test.js.snap
+++ b/Libraries/Components/Touchable/__tests__/__snapshots__/TouchableHighlight-test.js.snap
@@ -2,6 +2,14 @@
exports[`TouchableHighlight renders correctly 1`] = `
should render as expected 1`] = `
"selected": undefined,
}
}
+ accessibilityValue={
+ Object {
+ "max": undefined,
+ "min": undefined,
+ "now": undefined,
+ "text": undefined,
+ }
+ }
accessible={true}
focusable={false}
onClick={[Function]}
@@ -34,6 +42,14 @@ exports[` shoul
"selected": undefined,
}
}
+ accessibilityValue={
+ Object {
+ "max": undefined,
+ "min": undefined,
+ "now": undefined,
+ "text": undefined,
+ }
+ }
accessible={true}
focusable={false}
onClick={[Function]}
@@ -80,6 +104,14 @@ exports[` should be disabled when disab
"selected": undefined,
}
}
+ accessibilityValue={
+ Object {
+ "max": undefined,
+ "min": undefined,
+ "now": undefined,
+ "text": undefined,
+ }
+ }
accessible={true}
focusable={false}
onClick={[Function]}
@@ -149,6 +197,14 @@ exports[`TouchableWithoutFeedback renders correctly 1`] = `
"selected": undefined,
}
}
+ accessibilityValue={
+ Object {
+ "max": undefined,
+ "min": undefined,
+ "now": undefined,
+ "text": undefined,
+ }
+ }
accessible={true}
focusable={false}
onClick={[Function]}
diff --git a/Libraries/Components/Touchable/__tests__/__snapshots__/TouchableOpacity-test.js.snap b/Libraries/Components/Touchable/__tests__/__snapshots__/TouchableOpacity-test.js.snap
index 92d94f7a1630cb..17f2e7f6f764e0 100644
--- a/Libraries/Components/Touchable/__tests__/__snapshots__/TouchableOpacity-test.js.snap
+++ b/Libraries/Components/Touchable/__tests__/__snapshots__/TouchableOpacity-test.js.snap
@@ -11,6 +11,14 @@ exports[`TouchableOpacity renders correctly 1`] = `
"selected": undefined,
}
}
+ accessibilityValue={
+ Object {
+ "max": undefined,
+ "min": undefined,
+ "now": undefined,
+ "text": undefined,
+ }
+ }
accessible={true}
collapsable={false}
focusable={false}
@@ -44,6 +52,14 @@ exports[`TouchableOpacity renders in disabled state when a disabled prop is pass
"selected": undefined,
}
}
+ accessibilityValue={
+ Object {
+ "max": undefined,
+ "min": undefined,
+ "now": undefined,
+ "text": undefined,
+ }
+ }
accessible={true}
collapsable={false}
focusable={false}
@@ -77,6 +93,14 @@ exports[`TouchableOpacity renders in disabled state when a key disabled in acces
"selected": undefined,
}
}
+ accessibilityValue={
+ Object {
+ "max": undefined,
+ "min": undefined,
+ "now": undefined,
+ "text": undefined,
+ }
+ }
accessible={true}
collapsable={false}
focusable={false}
diff --git a/Libraries/Components/View/View.js b/Libraries/Components/View/View.js
index 9fbab16d0b8130..97020938e6d01b 100644
--- a/Libraries/Components/View/View.js
+++ b/Libraries/Components/View/View.js
@@ -131,6 +131,14 @@ const View: React.AbstractComponent<
treeitem: undefined,
};
+ const accessibilityValue = {
+ max: otherProps['aria-valuemax'] ?? otherProps.accessibilityValue?.max,
+ min: otherProps['aria-valuemin'] ?? otherProps.accessibilityValue?.min,
+ now: otherProps['aria-valuenow'] ?? otherProps.accessibilityValue?.now,
+ text: otherProps['aria-valuetext'] ?? otherProps.accessibilityValue?.text,
+ };
+ const restWithDefaultProps = {...otherProps, accessibilityValue};
+
const flattenedStyle = flattenStyle(style);
const newPointerEvents = flattenedStyle?.pointerEvents || pointerEvents;
@@ -153,7 +161,7 @@ const View: React.AbstractComponent<
? 'no-hide-descendants'
: importantForAccessibility
}
- {...restProps}
+ {...restWithDefaultProps}
style={style}
pointerEvents={newPointerEvents}
ref={forwardedRef}
diff --git a/Libraries/Components/View/ViewPropTypes.js b/Libraries/Components/View/ViewPropTypes.js
index 2f76343639869a..c6cb8655d50532 100644
--- a/Libraries/Components/View/ViewPropTypes.js
+++ b/Libraries/Components/View/ViewPropTypes.js
@@ -488,6 +488,15 @@ export type ViewProps = $ReadOnly<{|
accessibilityState?: ?AccessibilityState,
accessibilityValue?: ?AccessibilityValue,
+ /**
+ * alias for accessibilityState
+ * It represents textual description of a component's value, or for range-based components, such as sliders and progress bars.
+ */
+ 'aria-valuemax'?: ?AccessibilityValue['max'],
+ 'aria-valuemin'?: ?AccessibilityValue['min'],
+ 'aria-valuenow'?: ?AccessibilityValue['now'],
+ 'aria-valuetext'?: ?AccessibilityValue['text'],
+
/**
* Provides an array of custom actions available for accessibility.
*
diff --git a/Libraries/Components/__tests__/__snapshots__/Button-test.js.snap b/Libraries/Components/__tests__/__snapshots__/Button-test.js.snap
index 57c18ada171a0d..5b4294e0e8c850 100644
--- a/Libraries/Components/__tests__/__snapshots__/Button-test.js.snap
+++ b/Libraries/Components/__tests__/__snapshots__/Button-test.js.snap
@@ -12,6 +12,14 @@ exports[` should be disabled and it should set accessibilityState to d
"selected": undefined,
}
}
+ accessibilityValue={
+ Object {
+ "max": undefined,
+ "min": undefined,
+ "now": undefined,
+ "text": undefined,
+ }
+ }
accessible={true}
collapsable={false}
focusable={false}
@@ -70,6 +78,14 @@ exports[` should be disabled when disabled is empty and accessibilityS
"selected": undefined,
}
}
+ accessibilityValue={
+ Object {
+ "max": undefined,
+ "min": undefined,
+ "now": undefined,
+ "text": undefined,
+ }
+ }
accessible={true}
collapsable={false}
focusable={false}
@@ -128,6 +144,14 @@ exports[` should be disabled when disabled={true} and accessibilitySta
"selected": undefined,
}
}
+ accessibilityValue={
+ Object {
+ "max": undefined,
+ "min": undefined,
+ "now": undefined,
+ "text": undefined,
+ }
+ }
accessible={true}
collapsable={false}
focusable={false}
@@ -186,6 +210,14 @@ exports[` should be set importantForAccessibility={no-hide-descendants
"selected": undefined,
}
}
+ accessibilityValue={
+ Object {
+ "max": undefined,
+ "min": undefined,
+ "now": undefined,
+ "text": undefined,
+ }
+ }
accessible={true}
collapsable={false}
focusable={false}
@@ -240,6 +272,14 @@ exports[` should be set importantForAccessibility={no-hide-descendants
"selected": undefined,
}
}
+ accessibilityValue={
+ Object {
+ "max": undefined,
+ "min": undefined,
+ "now": undefined,
+ "text": undefined,
+ }
+ }
accessible={true}
collapsable={false}
focusable={false}
@@ -294,6 +334,14 @@ exports[` should not be disabled when disabled={false} and accessibili
"selected": undefined,
}
}
+ accessibilityValue={
+ Object {
+ "max": undefined,
+ "min": undefined,
+ "now": undefined,
+ "text": undefined,
+ }
+ }
accessible={true}
collapsable={false}
focusable={false}
@@ -348,6 +396,14 @@ exports[` should not be disabled when disabled={false} and accessibili
"selected": undefined,
}
}
+ accessibilityValue={
+ Object {
+ "max": undefined,
+ "min": undefined,
+ "now": undefined,
+ "text": undefined,
+ }
+ }
accessible={true}
collapsable={false}
focusable={false}
@@ -402,6 +458,14 @@ exports[` should overwrite accessibilityState with value of disabled p
"selected": undefined,
}
}
+ accessibilityValue={
+ Object {
+ "max": undefined,
+ "min": undefined,
+ "now": undefined,
+ "text": undefined,
+ }
+ }
accessible={true}
collapsable={false}
focusable={false}
@@ -460,6 +524,14 @@ exports[` should render as expected 1`] = `
"selected": undefined,
}
}
+ accessibilityValue={
+ Object {
+ "max": undefined,
+ "min": undefined,
+ "now": undefined,
+ "text": undefined,
+ }
+ }
accessible={true}
collapsable={false}
focusable={false}
diff --git a/packages/rn-tester/js/examples/Accessibility/AccessibilityExample.js b/packages/rn-tester/js/examples/Accessibility/AccessibilityExample.js
index 44dd674b9ddcdc..dc5ab8923c2218 100644
--- a/packages/rn-tester/js/examples/Accessibility/AccessibilityExample.js
+++ b/packages/rn-tester/js/examples/Accessibility/AccessibilityExample.js
@@ -930,6 +930,92 @@ class FakeSliderExample extends React.Component<{}, FakeSliderExampleState> {
}
}
+class FakeSliderExampleForAccessibilityValue extends React.Component<
+ {},
+ FakeSliderExampleState,
+> {
+ state: FakeSliderExampleState = {
+ current: 50,
+ textualValue: 'center',
+ };
+
+ increment: () => void = () => {
+ let newValue = this.state.current + 2;
+ if (newValue > 100) {
+ newValue = 100;
+ }
+ this.setState({
+ current: newValue,
+ });
+ };
+
+ decrement: () => void = () => {
+ let newValue = this.state.current - 2;
+ if (newValue < 0) {
+ newValue = 0;
+ }
+ this.setState({
+ current: newValue,
+ });
+ };
+
+ render(): React.Node {
+ return (
+
+ {
+ switch (event.nativeEvent.actionName) {
+ case 'increment':
+ this.increment();
+ break;
+ case 'decrement':
+ this.decrement();
+ break;
+ }
+ }}
+ aria-valuemax={100}
+ aria-valuemin={0}
+ aria-valuetext={'slider aria value text'}
+ aria-valuenow={this.state.current}>
+ Fake Slider
+
+ {
+ switch (event.nativeEvent.actionName) {
+ case 'increment':
+ if (this.state.textualValue === 'center') {
+ this.setState({textualValue: 'right'});
+ } else if (this.state.textualValue === 'left') {
+ this.setState({textualValue: 'center'});
+ }
+ break;
+ case 'decrement':
+ if (this.state.textualValue === 'center') {
+ this.setState({textualValue: 'left'});
+ } else if (this.state.textualValue === 'right') {
+ this.setState({textualValue: 'center'});
+ }
+ break;
+ }
+ }}
+ accessibilityValue={{text: this.state.textualValue}}>
+
+ Equalizer
+
+
+
+ );
+ }
+}
+
class AnnounceForAccessibility extends React.Component<{}> {
_handleOnPress = (): TimeoutID =>
setTimeout(
@@ -1309,6 +1395,12 @@ exports.examples = [
return ;
},
},
+ {
+ title: 'Fake SliderExample For AccessibilityValue',
+ render(): React.Element {
+ return ;
+ },
+ },
{
title: 'Check if the display options are enabled',
render(): React.Element {