🌈 Making Your App Talk to Everyone: React Native Accessibility
The Magic Door Story
Imagine you built the most amazing treehouse ever! It has slides, secret rooms, and a candy dispenser. But wait… what if your friend uses a wheelchair? What if another friend can’t see? Your awesome treehouse would be useless to them! 😢
Accessibility is like adding a magic door to your treehouse. This magic door changes itself to help EVERYONE enter and enjoy your creation. Some friends need a ramp. Some need audio descriptions. Some read right-to-left. The magic door handles it all!
In React Native, we have four magic tools to build this door:
- 🎤 AccessibilityInfo API - Asks the phone what help the user needs
- 🏷️ Accessibility Props - Labels that describe everything to assistive tools
- 📢 Screen Reader Support - Makes your app talk out loud
- ↔️ RTL Support - Flips your app for languages that read right-to-left
🎤 AccessibilityInfo API: The Phone Whisperer
What Is It?
Think of AccessibilityInfo as a spy that finds out what special settings the user has turned on. Is the screen reader active? Does the user need bigger text? This API tells you!
Why Do We Need It?
Imagine serving ice cream. Before scooping, you ask: “Any allergies?” That’s what AccessibilityInfo does - it asks the phone about the user’s needs BEFORE showing content.
Simple Example
import { AccessibilityInfo } from 'react-native';
// Check if screen reader is on
const checkScreenReader = async () => {
const isEnabled = await AccessibilityInfo
.isScreenReaderEnabled();
if (isEnabled) {
console.log('Screen reader is ON!');
}
};
Listening for Changes
// React to changes in real-time
useEffect(() => {
const listener = AccessibilityInfo
.addEventListener(
'screenReaderChanged',
(isEnabled) => {
setScreenReaderOn(isEnabled);
}
);
return () => listener.remove();
}, []);
Key Methods You’ll Use
| Method | What It Does |
|---|---|
isScreenReaderEnabled() |
Is VoiceOver/TalkBack on? |
isBoldTextEnabled() |
User wants bold text? |
isReduceMotionEnabled() |
User dislikes animations? |
announceForAccessibility() |
Speak a message out loud |
Real-World Magic
// Announce important updates
const onPurchaseComplete = () => {
AccessibilityInfo.announceForAccessibility(
'Purchase complete! Receipt sent to email.'
);
};
graph TD A["User Opens App"] --> B{Check AccessibilityInfo} B --> C["Screen Reader On?"] B --> D["Bold Text On?"] B --> E["Reduce Motion On?"] C --> F["Add extra labels"] D --> G["Use larger fonts"] E --> H["Disable animations"]
🏷️ Accessibility Props: Name Tags for Everything
What Are They?
Imagine going to a party where nobody has name tags. Confusing, right? Accessibility Props are name tags for every button, image, and text in your app. Screen readers read these tags out loud.
The Most Important Props
1. accessible - “Hey, I’m important!”
// Group items as one unit
<View accessible={true}>
<Text>John Doe</Text>
<Text>Online</Text>
</View>
// Screen reader says: "John Doe Online"
2. accessibilityLabel - “Call me this!”
// Without label: "Button"
// With label: "Add to cart, 29 dollars"
<TouchableOpacity
accessibilityLabel="Add to cart, 29 dollars"
>
<Icon name="cart" />
</TouchableOpacity>
3. accessibilityHint - “Here’s what I do!”
<TouchableOpacity
accessibilityLabel="Submit order"
accessibilityHint="Double tap to place order"
>
<Text>Submit</Text>
</TouchableOpacity>
4. accessibilityRole - “I’m a type of thing!”
// Tell the system what this element IS
<TouchableOpacity accessibilityRole="button">
<Text>Click Me</Text>
</TouchableOpacity>
// Common roles:
// button, link, image, header,
// checkbox, radio, slider, switch
5. accessibilityState - “Here’s my status!”
<TouchableOpacity
accessibilityRole="checkbox"
accessibilityState={{
checked: isChecked,
disabled: isDisabled
}}
>
<Text>Accept Terms</Text>
</TouchableOpacity>
Quick Reference Table
| Prop | Purpose | Example Value |
|---|---|---|
accessible |
Group elements | true |
accessibilityLabel |
Name it | "Profile picture" |
accessibilityHint |
Explain action | "Opens gallery" |
accessibilityRole |
Type of element | "button" |
accessibilityState |
Current status | {selected: true} |
graph TD A["UI Element"] --> B["accessible=true"] B --> C["accessibilityLabel"] C --> D["accessibilityHint"] D --> E["accessibilityRole"] E --> F["accessibilityState"] F --> G["Screen Reader<br/>Understands Everything!"]
📢 Screen Reader Support: Making Your App Speak
What Is a Screen Reader?
A screen reader is like a tour guide for blind users. It reads everything on screen out loud. On iOS it’s called VoiceOver. On Android it’s called TalkBack.
How Users Navigate
Screen reader users don’t see your beautiful design. They hear it! They swipe left/right to move between elements. Double-tap to activate.
Making Elements Focusable
// This becomes a "stop" for the screen reader
<View
accessible={true}
accessibilityLabel="Welcome message"
>
<Text>Hello! Ready to learn?</Text>
</View>
Hiding Decorative Elements
// Don't read this out loud - it's just decoration
<Image
source={decorativeLine}
accessibilityElementsHidden={true}
importantForAccessibility="no-hide-descendants"
/>
Managing Focus
import { findNodeHandle, AccessibilityInfo }
from 'react-native';
// Move focus to a specific element
const focusOnError = () => {
const node = findNodeHandle(errorRef.current);
AccessibilityInfo.setAccessibilityFocus(node);
};
Live Regions: Announce Updates
// When this text changes, announce it!
<Text accessibilityLiveRegion="polite">
{itemCount} items in cart
</Text>
// "polite" = wait for user to finish
// "assertive" = interrupt immediately
Best Practices Checklist
✅ Every image has a label or is hidden
✅ Buttons describe their action
✅ Form errors announce themselves
✅ Important updates use announceForAccessibility
✅ Focus moves logically through the screen
graph TD A["Screen Reader User"] --> B["Swipe Right"] B --> C["Read Element 1"] C --> D["Swipe Right"] D --> E["Read Element 2"] E --> F["Double Tap"] F --> G["Activate Element"] G --> H["Announce Result"]
↔️ RTL Support: Flipping Your App
What Is RTL?
Some languages read Right-To-Left: Arabic, Hebrew, Persian, Urdu. When users choose these languages, your ENTIRE app should flip like a mirror!
The Magic of I18nManager
import { I18nManager } from 'react-native';
// Check current direction
console.log(I18nManager.isRTL);
// true or false
// Force RTL (requires app restart)
I18nManager.forceRTL(true);
I18nManager.allowRTL(true);
Automatic Layout Flipping
Good news! Flexbox direction flips automatically!
// This row flips in RTL languages
<View style={{ flexDirection: 'row' }}>
<Icon name="arrow" />
<Text>Next</Text>
</View>
// LTR: [→] Next
// RTL: Next [←]
Prevent Flipping When Needed
Some things shouldn’t flip (like video players):
// Keep this element always LTR
<View style={{
flexDirection: 'row',
// STOP! Don't flip this!
writingDirection: 'ltr'
}}>
<PlayButton />
<Scrubber />
</View>
Text Alignment
// Auto-align based on language
<Text style={{ textAlign: 'auto' }}>
This aligns correctly in any language
</Text>
// Explicit control
<Text style={{ writingDirection: 'rtl' }}>
עברית
</Text>
Handling Icons
// Flip arrow icons in RTL
<Image
source={arrowIcon}
style={{
transform: [{
scaleX: I18nManager.isRTL ? -1 : 1
}]
}}
/>
RTL Testing Tips
- Add RTL language in phone settings
- Or force RTL in your app temporarily
- Check ALL screens flip correctly
- Icons that “point” should flip too
graph TD A["User Selects Arabic"] --> B["I18nManager.isRTL = true"] B --> C["Flexbox Rows Flip"] B --> D["Text Aligns Right"] B --> E["Margins Swap"] C --> F["App Looks Natural in RTL"] D --> F E --> F
🎯 Putting It All Together
Here’s a complete accessible component:
const ProductCard = ({ product }) => {
const screenReaderOn = useScreenReader();
return (
<TouchableOpacity
accessible={true}
accessibilityRole="button"
accessibilityLabel={
`${product.name}, ${product.price}`
}
accessibilityHint="Double tap to view details"
accessibilityState={{
selected: product.isSelected
}}
style={{
flexDirection: 'row' // Auto-flips in RTL
}}
>
<Image
source={product.image}
accessibilityLabel={product.imageDesc}
/>
<View>
<Text style={{ textAlign: 'auto' }}>
{product.name}
</Text>
<Text>{product.price}</Text>
</View>
</TouchableOpacity>
);
};
🌟 Remember These Golden Rules
- Ask First → Use AccessibilityInfo to know user needs
- Label Everything → Give every element a clear name
- Announce Changes → Tell users what happened
- Flip Gracefully → Support RTL languages naturally
When you build accessible apps, you’re not just following rules. You’re opening doors for millions of people who otherwise couldn’t use your creation. That’s not just good coding - that’s being a hero! 🦸♀️
“The power of the Web is in its universality. Access by everyone regardless of disability is an essential aspect.” — Tim Berners-Lee
