Skip to content

Commit 98d84e5

Browse files
ankit-tailorfacebook-github-bot
authored andcommitted
Feat/accessibility state alias (#34524)
Summary: This adds aliasing for accessibility state, it's used as requested on #34424. - [aria-disabled](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-disabled) to equivalent [accessibilityState.disabled](https://reactnative.dev/docs/accessibility#accessibilitystate) - [aria-busy](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-busy) to equivalent [accessibilityState.busy](https://reactnative.dev/docs/accessibility#accessibilitystate) - [aria-checked](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-checked) to equivalent [accessibilityState.checked](https://reactnative.dev/docs/accessibility#accessibilitystate) - [aria-expanded](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-expanded) to equivalent [accessibilityState.expanded](https://reactnative.dev/docs/accessibility#accessibilitystate) - [aria-selected](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-selected) to equivalent [accessibilityState.selected](https://reactnative.dev/docs/accessibility#accessibilitystate) ## Changelog [General] [Added] - Add aria-disabled, aria-busy, aria-checked, aria-expanded and aria-selected prop to core components <!-- Help reviewers and the release process by writing your own changelog entry. For an example, see: https://reactnative.dev/contributing/changelogs-in-pull-requests --> Pull Request resolved: #34524 Test Plan: ```js <View aria-disabled={true} aria-selected={false} aria-checked={true} aria-expanded={true} aria-busy={true} style={{backgroundColor: '#527FE4', padding: 5}}> <Text style={{fontSize: 11}}>Blue background</Text> </View> ``` Reviewed By: cipolleschi Differential Revision: D39137790 Pulled By: jacdebug fbshipit-source-id: 27b5c56e91731ba36bb4754d9862286a7a8191bc
1 parent a562216 commit 98d84e5

File tree

21 files changed

+475
-53
lines changed

21 files changed

+475
-53
lines changed

Libraries/Components/Button.js

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,17 @@ type ButtonProps = $ReadOnly<{|
147147
onAccessibilityAction?: ?(event: AccessibilityActionEvent) => mixed,
148148
accessibilityState?: ?AccessibilityState,
149149

150+
/**
151+
* alias for accessibilityState
152+
*
153+
* see https://reactnative.dev/docs/accessibility#accessibilitystate
154+
*/
155+
'aria-busy'?: ?boolean,
156+
'aria-checked'?: ?boolean,
157+
'aria-disabled'?: ?boolean,
158+
'aria-expanded'?: ?boolean,
159+
'aria-selected'?: ?boolean,
160+
150161
/**
151162
* [Android] Controlling if a view fires accessibility events and if it is reported to accessibility services.
152163
*/
@@ -270,6 +281,12 @@ class Button extends React.Component<ButtonProps> {
270281
render(): React.Node {
271282
const {
272283
accessibilityLabel,
284+
accessibilityState,
285+
'aria-busy': ariaBusy,
286+
'aria-checked': ariaChecked,
287+
'aria-disabled': ariaDisabled,
288+
'aria-expanded': ariaExpanded,
289+
'aria-selected': ariaSelected,
273290
importantForAccessibility,
274291
color,
275292
onPress,
@@ -298,15 +315,23 @@ class Button extends React.Component<ButtonProps> {
298315
}
299316
}
300317

318+
let _accessibilityState = {
319+
busy: ariaBusy ?? accessibilityState?.busy,
320+
checked: ariaChecked ?? accessibilityState?.checked,
321+
disabled: ariaDisabled ?? accessibilityState?.disabled,
322+
expanded: ariaExpanded ?? accessibilityState?.expanded,
323+
selected: ariaSelected ?? accessibilityState?.selected,
324+
};
325+
301326
const disabled =
302327
this.props.disabled != null
303328
? this.props.disabled
304-
: this.props.accessibilityState?.disabled;
329+
: _accessibilityState?.disabled;
305330

306-
const accessibilityState =
307-
disabled !== this.props.accessibilityState?.disabled
308-
? {...this.props.accessibilityState, disabled}
309-
: this.props.accessibilityState;
331+
_accessibilityState =
332+
disabled !== _accessibilityState?.disabled
333+
? {..._accessibilityState, disabled}
334+
: _accessibilityState;
310335

311336
if (disabled) {
312337
buttonStyles.push(styles.buttonDisabled);
@@ -337,7 +362,7 @@ class Button extends React.Component<ButtonProps> {
337362
accessibilityHint={accessibilityHint}
338363
accessibilityLanguage={accessibilityLanguage}
339364
accessibilityRole="button"
340-
accessibilityState={accessibilityState}
365+
accessibilityState={_accessibilityState}
341366
importantForAccessibility={_importantForAccessibility}
342367
hasTVPreferredFocus={hasTVPreferredFocus}
343368
nextFocusDown={nextFocusDown}

Libraries/Components/Pressable/Pressable.js

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,17 @@ type Props = $ReadOnly<{|
5252
accessibilityValue?: ?AccessibilityValue,
5353
accessibilityViewIsModal?: ?boolean,
5454
accessible?: ?boolean,
55+
56+
/**
57+
* alias for accessibilityState
58+
*
59+
* see https://reactnative.dev/docs/accessibility#accessibilitystate
60+
*/
61+
'aria-busy'?: ?boolean,
62+
'aria-checked'?: ?boolean,
63+
'aria-disabled'?: ?boolean,
64+
'aria-expanded'?: ?boolean,
65+
'aria-selected'?: ?boolean,
5566
/**
5667
* A value indicating whether the accessibility elements contained within
5768
* this accessibility element are hidden.
@@ -179,9 +190,15 @@ type Props = $ReadOnly<{|
179190
* LTI update could not be added via codemod */
180191
function Pressable(props: Props, forwardedRef): React.Node {
181192
const {
182-
accessible,
193+
accessibilityState,
183194
android_disableSound,
184195
android_ripple,
196+
accessible,
197+
'aria-busy': ariaBusy,
198+
'aria-checked': ariaChecked,
199+
'aria-disabled': ariaDisabled,
200+
'aria-expanded': ariaExpanded,
201+
'aria-selected': ariaSelected,
185202
cancelable,
186203
children,
187204
delayHoverIn,
@@ -210,16 +227,22 @@ function Pressable(props: Props, forwardedRef): React.Node {
210227

211228
const [pressed, setPressed] = usePressState(testOnly_pressed === true);
212229

213-
const accessibilityState =
214-
disabled != null
215-
? {...props.accessibilityState, disabled}
216-
: props.accessibilityState;
230+
let _accessibilityState = {
231+
busy: ariaBusy ?? accessibilityState?.busy,
232+
checked: ariaChecked ?? accessibilityState?.checked,
233+
disabled: ariaDisabled ?? accessibilityState?.disabled,
234+
expanded: ariaExpanded ?? accessibilityState?.expanded,
235+
selected: ariaSelected ?? accessibilityState?.selected,
236+
};
237+
238+
_accessibilityState =
239+
disabled != null ? {..._accessibilityState, disabled} : _accessibilityState;
217240

218241
const restPropsWithDefaults: React.ElementConfig<typeof View> = {
219242
...restProps,
220243
...android_rippleConfig?.viewProps,
221244
accessible: accessible !== false,
222-
accessibilityState,
245+
accessibilityState: _accessibilityState,
223246
focusable: focusable !== false,
224247
hitSlop,
225248
};

Libraries/Components/Pressable/__tests__/__snapshots__/Pressable-test.js.snap

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22

33
exports[`<Pressable /> should render as expected: should deep render when mocked (please verify output manually) 1`] = `
44
<View
5+
accessibilityState={
6+
Object {
7+
"busy": undefined,
8+
"checked": undefined,
9+
"disabled": undefined,
10+
"expanded": undefined,
11+
"selected": undefined,
12+
}
13+
}
514
accessible={true}
615
collapsable={false}
716
focusable={true}
@@ -21,6 +30,15 @@ exports[`<Pressable /> should render as expected: should deep render when mocked
2130

2231
exports[`<Pressable /> should render as expected: should deep render when not mocked (please verify output manually) 1`] = `
2332
<View
33+
accessibilityState={
34+
Object {
35+
"busy": undefined,
36+
"checked": undefined,
37+
"disabled": undefined,
38+
"expanded": undefined,
39+
"selected": undefined,
40+
}
41+
}
2442
accessible={true}
2543
collapsable={false}
2644
focusable={true}
@@ -54,7 +72,11 @@ exports[`<Pressable disabled={true} /> should be disabled when disabled is true:
5472
<View
5573
accessibilityState={
5674
Object {
75+
"busy": undefined,
76+
"checked": undefined,
5777
"disabled": true,
78+
"expanded": undefined,
79+
"selected": undefined,
5880
}
5981
}
6082
accessible={true}
@@ -78,7 +100,11 @@ exports[`<Pressable disabled={true} /> should be disabled when disabled is true:
78100
<View
79101
accessibilityState={
80102
Object {
103+
"busy": undefined,
104+
"checked": undefined,
81105
"disabled": true,
106+
"expanded": undefined,
107+
"selected": undefined,
82108
}
83109
}
84110
accessible={true}
@@ -118,7 +144,11 @@ exports[`<Pressable disabled={true} accessibilityState={{}} /> should be disable
118144
<View
119145
accessibilityState={
120146
Object {
147+
"busy": undefined,
148+
"checked": undefined,
121149
"disabled": true,
150+
"expanded": undefined,
151+
"selected": undefined,
122152
}
123153
}
124154
accessible={true}
@@ -142,7 +172,11 @@ exports[`<Pressable disabled={true} accessibilityState={{}} /> should be disable
142172
<View
143173
accessibilityState={
144174
Object {
175+
"busy": undefined,
176+
"checked": undefined,
145177
"disabled": true,
178+
"expanded": undefined,
179+
"selected": undefined,
146180
}
147181
}
148182
accessible={true}
@@ -184,8 +218,11 @@ exports[`<Pressable disabled={true} accessibilityState={{checked: true}} /> shou
184218
<View
185219
accessibilityState={
186220
Object {
221+
"busy": undefined,
187222
"checked": true,
188223
"disabled": true,
224+
"expanded": undefined,
225+
"selected": undefined,
189226
}
190227
}
191228
accessible={true}
@@ -209,8 +246,11 @@ exports[`<Pressable disabled={true} accessibilityState={{checked: true}} /> shou
209246
<View
210247
accessibilityState={
211248
Object {
249+
"busy": undefined,
212250
"checked": true,
213251
"disabled": true,
252+
"expanded": undefined,
253+
"selected": undefined,
214254
}
215255
}
216256
accessible={true}
@@ -260,7 +300,11 @@ exports[`<Pressable disabled={true} accessibilityState={{disabled: false}} /> sh
260300
<View
261301
accessibilityState={
262302
Object {
303+
"busy": undefined,
304+
"checked": undefined,
263305
"disabled": true,
306+
"expanded": undefined,
307+
"selected": undefined,
264308
}
265309
}
266310
accessible={true}
@@ -284,7 +328,11 @@ exports[`<Pressable disabled={true} accessibilityState={{disabled: false}} /> sh
284328
<View
285329
accessibilityState={
286330
Object {
331+
"busy": undefined,
332+
"checked": undefined,
287333
"disabled": true,
334+
"expanded": undefined,
335+
"selected": undefined,
288336
}
289337
}
290338
accessible={true}

Libraries/Components/TextInput/TextInput.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1339,6 +1339,14 @@ function InternalTextInput(props: Props): React.Node {
13391339
// so omitting onBlur and onFocus pressability handlers here.
13401340
const {onBlur, onFocus, ...eventHandlers} = usePressability(config) || {};
13411341

1342+
const _accessibilityState = {
1343+
busy: props['aria-busy'] ?? props.accessibilityState?.busy,
1344+
checked: props['aria-checked'] ?? props.accessibilityState?.checked,
1345+
disabled: props['aria-disabled'] ?? props.accessibilityState?.disabled,
1346+
expanded: props['aria-expanded'] ?? props.accessibilityState?.expanded,
1347+
selected: props['aria-selected'] ?? props.accessibilityState?.selected,
1348+
};
1349+
13421350
if (Platform.OS === 'ios') {
13431351
const RCTTextInputView =
13441352
props.multiline === true
@@ -1360,6 +1368,7 @@ function InternalTextInput(props: Props): React.Node {
13601368
{...props}
13611369
{...eventHandlers}
13621370
accessible={accessible}
1371+
accessibilityState={_accessibilityState}
13631372
submitBehavior={submitBehavior}
13641373
caretHidden={caretHidden}
13651374
dataDetectorTypes={props.dataDetectorTypes}
@@ -1407,6 +1416,7 @@ function InternalTextInput(props: Props): React.Node {
14071416
{...props}
14081417
{...eventHandlers}
14091418
accessible={accessible}
1419+
accessibilityState={_accessibilityState}
14101420
autoCapitalize={autoCapitalize}
14111421
submitBehavior={submitBehavior}
14121422
caretHidden={caretHidden}

Libraries/Components/TextInput/__tests__/__snapshots__/TextInput-test.js.snap

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22

33
exports[`TextInput tests should render as expected: should deep render when mocked (please verify output manually) 1`] = `
44
<RCTSinglelineTextInputView
5+
accessibilityState={
6+
Object {
7+
"busy": undefined,
8+
"checked": undefined,
9+
"disabled": undefined,
10+
"expanded": undefined,
11+
"selected": undefined,
12+
}
13+
}
514
accessible={true}
615
allowFontScaling={true}
716
focusable={true}
@@ -31,6 +40,15 @@ exports[`TextInput tests should render as expected: should deep render when mock
3140

3241
exports[`TextInput tests should render as expected: should deep render when not mocked (please verify output manually) 1`] = `
3342
<RCTSinglelineTextInputView
43+
accessibilityState={
44+
Object {
45+
"busy": undefined,
46+
"checked": undefined,
47+
"disabled": undefined,
48+
"expanded": undefined,
49+
"selected": undefined,
50+
}
51+
}
3452
accessible={true}
3553
allowFontScaling={true}
3654
focusable={true}

Libraries/Components/Touchable/TouchableBounce.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,18 @@ class TouchableBounce extends React.Component<Props, State> {
131131
const {onBlur, onFocus, ...eventHandlersWithoutBlurAndFocus} =
132132
this.state.pressability.getEventHandlers();
133133

134+
const _accessibilityState = {
135+
busy: this.props['aria-busy'] ?? this.props.accessibilityState?.busy,
136+
checked:
137+
this.props['aria-checked'] ?? this.props.accessibilityState?.checked,
138+
disabled:
139+
this.props['aria-disabled'] ?? this.props.accessibilityState?.disabled,
140+
expanded:
141+
this.props['aria-expanded'] ?? this.props.accessibilityState?.expanded,
142+
selected:
143+
this.props['aria-selected'] ?? this.props.accessibilityState?.selected,
144+
};
145+
134146
return (
135147
<Animated.View
136148
style={[{transform: [{scale: this.state.scale}]}, this.props.style]}
@@ -139,7 +151,7 @@ class TouchableBounce extends React.Component<Props, State> {
139151
accessibilityHint={this.props.accessibilityHint}
140152
accessibilityLanguage={this.props.accessibilityLanguage}
141153
accessibilityRole={this.props.accessibilityRole}
142-
accessibilityState={this.props.accessibilityState}
154+
accessibilityState={_accessibilityState}
143155
accessibilityActions={this.props.accessibilityActions}
144156
onAccessibilityAction={this.props.onAccessibilityAction}
145157
accessibilityValue={this.props.accessibilityValue}

0 commit comments

Comments
 (0)