Permalink
Browse files

Add accessibilityHint for iOS (#18093)

Summary:
This adds the accessibilityHint for View, Text and Touchable* on iOS.
The accessibilityHint provides some more information about an element
when the accessibilityLabel is not enough.

The accessibilityHint is a core accessibility property on iOS.

From https://developer.apple.com/documentation/objectivec/nsobject/1615093-accessibilityhint:
> An accessibility hint helps users understand what will happen when they perform an action on the accessibility element when that result is not obvious from the accessibility label.

Related issue: #14706

The npm scripts `test`, `flow`, `lint` and `prettier` are satisfied.

I added a couple of examples to the RNTester app. The Accessibility Inspector on Mac helps debugging accessibility stuff on a simulator, but it does not show the accessibilityHint. Therefore I tested the RNTester app on an iPhone 8 device using VoiceOver to verify the hint functionality. It works fine, and I've tested disabling and enabling "read hints" in the VoiceOver settings on the phone.

facebook/react-native-website#222

[IOS][FEATURE][Accessibility] - Add accessibilityHint for View, Text, Touchable* on iOS
Closes #18093

Reviewed By: hramos

Differential Revision: D7230780

Pulled By: ziqichen6

fbshipit-source-id: 172ad28dc9ae2b67ea256100f6acb939f2466d0b
  • Loading branch information...
draperunner authored and facebook-github-bot committed Jul 26, 2018
1 parent b7bb25f commit 253b29dbd8ddb11824866e423c00a4a68bb856f3
@@ -160,6 +160,7 @@ const TouchableBounce = ((createReactClass({
style={[{transform: [{scale: this.state.scale}]}, this.props.style]}
accessible={this.props.accessible !== false}
accessibilityLabel={this.props.accessibilityLabel}
accessibilityHint={this.props.accessibilityHint}
accessibilityComponentType={this.props.accessibilityComponentType}
accessibilityTraits={this.props.accessibilityTraits}
nativeID={this.props.nativeID}
@@ -348,6 +348,7 @@ const TouchableHighlight = ((createReactClass({
<View
accessible={this.props.accessible !== false}
accessibilityLabel={this.props.accessibilityLabel}
accessibilityHint={this.props.accessibilityHint}
accessibilityComponentType={this.props.accessibilityComponentType}
accessibilityTraits={this.props.accessibilityTraits}
style={StyleSheet.compose(
@@ -256,6 +256,7 @@ const TouchableOpacity = ((createReactClass({
<Animated.View
accessible={this.props.accessible !== false}
accessibilityLabel={this.props.accessibilityLabel}
accessibilityHint={this.props.accessibilityHint}
accessibilityComponentType={this.props.accessibilityComponentType}
accessibilityTraits={this.props.accessibilityTraits}
style={[this.props.style, {opacity: this.state.anim}]}
@@ -43,6 +43,7 @@ export type Props = $ReadOnly<{|
| string
| Array<any>
| any,
accessibilityHint?: string,
accessibilityTraits?: ?AccessibilityTraitsFlow,
children?: ?React.Node,
delayLongPress?: ?number,
@@ -75,6 +76,7 @@ const TouchableWithoutFeedback = ((createReactClass({
propTypes: {
accessible: PropTypes.bool,
accessibilityLabel: PropTypes.node,
accessibilityHint: PropTypes.string,
accessibilityComponentType: PropTypes.oneOf(AccessibilityComponentTypes),
accessibilityTraits: PropTypes.oneOfType([
PropTypes.oneOf(AccessibilityTraits),
@@ -238,6 +240,7 @@ const TouchableWithoutFeedback = ((createReactClass({
return (React: any).cloneElement(child, {
accessible: this.props.accessible !== false,
accessibilityLabel: this.props.accessibilityLabel,
accessibilityHint: this.props.accessibilityHint,
accessibilityComponentType: this.props.accessibilityComponentType,
accessibilityTraits: this.props.accessibilityTraits,
nativeID: this.props.nativeID,
@@ -24,6 +24,7 @@ ReactNativeViewAttributes.UIView = {
accessibilityRole: true,
accessibilityStates: true,
accessibilityTraits: true,
accessibilityHint: true,
importantForAccessibility: true,
nativeID: true,
testID: true,
@@ -87,6 +87,7 @@ export type ViewProps = $ReadOnly<{|
| string
| Array<any>
| any,
accessibilityHint?: string,
accessibilityActions?: Array<string>,
accessibilityComponentType?: AccessibilityComponentType,
accessibilityLiveRegion?: 'none' | 'polite' | 'assertive',
@@ -128,6 +129,17 @@ module.exports = {
*/
accessibilityLabel: PropTypes.node,
/**
* An accessibility hint helps users understand what will happen when they perform
* an action on the accessibility element when that result is not obvious from the
* accessibility label.
*
* @platform ios
*
* See http://facebook.github.io/react-native/docs/view.html#accessibilityHint
*/
accessibilityHint: PropTypes.string,
/**
* Provides an array of custom actions available for accessibility.
*
@@ -238,7 +238,7 @@ - (BOOL)canPerformAction:(SEL)action withSender:(id)sender
if (_selectable && action == @selector(copy:)) {
return YES;
}
return [self.nextResponder canPerformAction:action withSender:sender];
}
@@ -12,7 +12,7 @@
var React = require('react');
var ReactNative = require('react-native');
var {AccessibilityInfo, Text, View} = ReactNative;
var {AccessibilityInfo, Text, View, TouchableOpacity} = ReactNative;
class AccessibilityIOSExample extends React.Component<{}> {
render() {
@@ -39,6 +39,31 @@ class AccessibilityIOSExample extends React.Component<{}> {
<Text accessibilityLabel="Test of accessibilityLabel" accessible={true}>
This text component's accessibilityLabel is set explicitly.
</Text>
<View
accessibilityLabel="Test of accessibilityHint"
accessibilityHint="The hint provides more info than the label does"
accessible={true}>
<Text>
This view component has both an accessibilityLabel and an
accessibilityHint explicitly set.
</Text>
</View>
<Text
accessibilityLabel="Test of accessibilityHint"
accessibilityHint="The hint provides more info than the label does">
This text component has both an accessibilityLabel and an
accessibilityHint explicitly set.
</Text>
<TouchableOpacity
accessibilityLabel="Test of accessibilityHint"
accessibilityHint="The hint provides more info than the label does">
<View>
<Text>
This button has both an accessibilityLabel and an
accessibilityHint explicitly set.
</Text>
</View>
</TouchableOpacity>
<View accessibilityElementsHidden={true}>
<Text>
This view's children are hidden from the accessibility tree
@@ -111,6 +111,7 @@ - (RCTShadowView *)shadowView
RCT_REMAP_VIEW_PROPERTY(accessible, reactAccessibilityElement.isAccessibilityElement, BOOL)
RCT_REMAP_VIEW_PROPERTY(accessibilityActions, reactAccessibilityElement.accessibilityActions, NSString)
RCT_REMAP_VIEW_PROPERTY(accessibilityLabel, reactAccessibilityElement.accessibilityLabel, NSString)
RCT_REMAP_VIEW_PROPERTY(accessibilityHint, reactAccessibilityElement.accessibilityHint, NSString)
RCT_REMAP_VIEW_PROPERTY(accessibilityTraits, reactAccessibilityElement.accessibilityTraits, UIAccessibilityTraits)
RCT_REMAP_VIEW_PROPERTY(accessibilityViewIsModal, reactAccessibilityElement.accessibilityViewIsModal, BOOL)
RCT_REMAP_VIEW_PROPERTY(accessibilityElementsHidden, reactAccessibilityElement.accessibilityElementsHidden, BOOL)

0 comments on commit 253b29d

Please sign in to comment.