โš›๏ธ React Native Accessibility

Implement accessible React Native applications using built-in accessibility props and platform-specific APIs.

๐ŸŽฏ Why React Native Accessibility Matters

React Native provides accessibility props that map to platform-specific accessibility features, allowing you to create accessible apps that work seamlessly with TalkBack (Android) and VoiceOver (iOS).

๐Ÿ’ป Implementation

Basic Accessibility Props

import React from 'react';
import { View, Text, TouchableOpacity } from 'react-native';

const AccessibleButton = ({ title, onPress, accessibilityLabel }) => {
  return (
    <TouchableOpacity
      onPress={onPress}
      accessibilityRole="button"
      accessibilityLabel={accessibilityLabel || title}
      accessibilityHint="Double tap to activate"
      style={{
        minHeight: 44,
        minWidth: 44,
        padding: 12,
        backgroundColor: '#007AFF',
        borderRadius: 8,
      }}
    >
      <Text style={{ color: 'white', textAlign: 'center' }}>
        {title}
      </Text>
    </TouchableOpacity>
  );
};

export default AccessibleButton;

Accessible Form Input

import React, { useState } from 'react';
import { View, Text, TextInput, TouchableOpacity } from 'react-native';

const AccessibleForm = () => {
  const [email, setEmail] = useState('');
  const [error, setError] = useState('');

  const validateEmail = () => {
    if (!email.includes('@')) {
      setError('Please enter a valid email address');
    } else {
      setError('');
    }
  };

  return (
    <View style={{ padding: 20 }}>
      <Text
        accessibilityRole="header"
        style={{ fontSize: 18, fontWeight: 'bold', marginBottom: 10 }}
      >
        Contact Form
      </Text>
      
      <Text
        accessibilityRole="text"
        style={{ marginBottom: 5 }}
      >
        Email Address
      </Text>
      
      <TextInput
        value={email}
        onChangeText={setEmail}
        onBlur={validateEmail}
        placeholder="Enter your email"
        accessibilityLabel="Email address input"
        accessibilityHint="Enter your email address"
        accessibilityRequired={true}
        style={{
          borderWidth: 1,
          borderColor: error ? 'red' : '#ccc',
          padding: 12,
          borderRadius: 8,
          marginBottom: 10,
        }}
      />
      
      {error ? (
        <Text
          accessibilityRole="alert"
          accessibilityLiveRegion="polite"
          style={{ color: 'red', marginBottom: 10 }}
        >
          {error}
        </Text>
      ) : null}
      
      <TouchableOpacity
        onPress={validateEmail}
        accessibilityRole="button"
        accessibilityLabel="Submit form"
        style={{
          backgroundColor: '#007AFF',
          padding: 12,
          borderRadius: 8,
          alignItems: 'center',
        }}
      >
        <Text style={{ color: 'white', fontWeight: 'bold' }}>
          Submit
        </Text>
      </TouchableOpacity>
    </View>
  );
};

export default AccessibleForm;

Dynamic Type Support

import React from 'react';
import { View, Text, useWindowDimensions } from 'react-native';

const DynamicTypeText = ({ children, style, ...props }) => {
  const { fontScale } = useWindowDimensions();
  
  // Ensure minimum readable size
  const baseFontSize = style?.fontSize || 16;
  const scaledFontSize = Math.max(baseFontSize * fontScale, 12);
  
  return (
    <Text
      style={[
        style,
        { fontSize: scaledFontSize }
      ]}
      allowFontScaling={true}
      {...props}
    >
      {children}
    </Text>
  );
};

const ResponsiveLayout = () => {
  return (
    <View style={{ padding: 20 }}>
      <DynamicTypeText
        accessibilityRole="header"
        style={{ fontSize: 24, fontWeight: 'bold', marginBottom: 16 }}
      >
        Welcome to Our App
      </DynamicTypeText>
      
      <DynamicTypeText
        accessibilityRole="text"
        style={{ fontSize: 16, lineHeight: 24 }}
      >
        This text will scale with the user's font size preferences while maintaining readability.
      </DynamicTypeText>
    </View>
  );
};

export default ResponsiveLayout;

Accessible Image with Description

import React from 'react';
import { View, Image, Text } from 'react-native';

const AccessibleImage = ({ 
  source, 
  alt, 
  isDecorative = false,
  style 
}) => {
  if (isDecorative) {
    return (
      <Image
        source={source}
        style={style}
        accessibilityRole="image"
        accessibilityLabel=""
        accessibilityElementsHidden={true}
      />
    );
  }

  return (
    <View>
      <Image
        source={source}
        style={style}
        accessibilityRole="image"
        accessibilityLabel={alt}
        accessibilityHint="Image"
      />
      {alt && (
        <Text
          accessibilityRole="text"
          style={{ fontSize: 12, color: '#666', marginTop: 4 }}
        >
          {alt}
        </Text>
      )}
    </View>
  );
};

export default AccessibleImage;

โœ… Best Practices

Do's

  • โœ“Use semantic accessibility roles
  • โœ“Provide meaningful accessibility labels
  • โœ“Set minimum touch target sizes (44x44 points)
  • โœ“Support Dynamic Type scaling
  • โœ“Test with both TalkBack and VoiceOver

Don'ts

  • โœ—Rely only on visual cues
  • โœ—Use generic accessibility labels
  • โœ—Ignore platform-specific behaviors
  • โœ—Override user font size preferences
  • โœ—Create touch targets smaller than 44x44 points

๐Ÿงช Testing Steps

Android Testing

  1. 1Enable TalkBack: Settings > Accessibility > TalkBack
  2. 2Test Navigation: Use swipe gestures to navigate
  3. 3Verify Announcements: Check that labels are descriptive
  4. 4Test Touch Targets: Ensure easy to tap

iOS Testing

  1. 1Enable VoiceOver: Settings > Accessibility > VoiceOver
  2. 2Test Navigation: Use swipe gestures to navigate
  3. 3Verify Announcements: Check that labels are descriptive
  4. 4Test Touch Targets: Ensure easy to tap

๐Ÿ” Common Pitfalls

Missing Labels

Images and buttons without accessibility labels

Generic Roles

Using "button" for all interactive elements

Small Touch Targets

Elements smaller than 44x44 points

No Error Handling

Forms without proper error announcements

๐Ÿ“ฑ Platform-Specific Behavior

Android

Maps to TalkBack and accessibility services

iOS

Maps to VoiceOver and accessibility features

Cross-platform

Maintains consistency across platforms

๐Ÿ“š References

React Native Accessibility Docs โ†’

Official React Native accessibility documentation

React Native Accessibility Props โ†’

Complete list of accessibility properties

Platform-Specific Accessibility โ†’

Platform-specific accessibility implementations