# Mobile Accessibility ## Overview Mobile accessibility ensures apps work for users with disabilities on iOS and Android devices. This includes support for screen readers (VoiceOver, TalkBack), motor impairments, and various visual disabilities. ## Touch Target Sizing ### Minimum Sizes ```css /* WCAG 2.2 Level AA: 24x24px minimum */ .interactive-element { min-width: 24px; min-height: 24px; } /* WCAG 2.2 Level AAA / Apple HIG / Material Design: 44x44dp */ .touch-target { min-width: 44px; min-height: 44px; } /* Android Material Design: 48x48dp recommended */ .android-touch-target { min-width: 48px; min-height: 48px; } ``` ### Touch Target Spacing ```tsx // Ensure adequate spacing between touch targets function ButtonGroup({ buttons }) { return (
{/* 12px minimum gap */} {buttons.map((btn) => ( ))}
); } // Expanding hit area without changing visual size function IconButton({ icon, label, onClick }) { return ( ); } ``` ## iOS VoiceOver ### React Native Accessibility Props ```tsx import { View, Text, TouchableOpacity, AccessibilityInfo } from 'react-native'; // Basic accessible button function AccessibleButton({ onPress, title, hint }) { return ( {title} ); } // Complex component with grouped content function ProductCard({ product }) { return ( { switch (event.nativeEvent.actionName) { case 'addToCart': addToCart(product); break; case 'activate': viewDetails(product); break; } }} > {product.name} {product.price} ); } // Announcing dynamic changes function Counter() { const [count, setCount] = useState(0); const increment = () => { setCount((prev) => prev + 1); AccessibilityInfo.announceForAccessibility(`Count is now ${count + 1}`); }; return ( Count: {count} + ); } ``` ### SwiftUI Accessibility ```swift import SwiftUI struct AccessibleButton: View { let title: String let action: () -> Void var body: some View { Button(action: action) { Text(title) } .accessibilityLabel(title) .accessibilityHint("Double tap to activate") .accessibilityAddTraits(.isButton) } } struct ProductCard: View { let product: Product var body: some View { VStack { AsyncImage(url: product.imageURL) .accessibilityHidden(true) // Image is decorative Text(product.name) Text(product.price.formatted(.currency(code: "USD"))) } .accessibilityElement(children: .combine) .accessibilityLabel("\(product.name), \(product.price.formatted(.currency(code: "USD")))") .accessibilityHint("Double tap to view details") .accessibilityAction(named: "Add to cart") { addToCart(product) } } } // Custom accessibility rotor struct DocumentView: View { let sections: [Section] var body: some View { ScrollView { ForEach(sections) { section in Text(section.title) .font(.headline) .accessibilityAddTraits(.isHeader) Text(section.content) } } .accessibilityRotor("Headings") { ForEach(sections) { section in AccessibilityRotorEntry(section.title, id: section.id) } } } } ``` ## Android TalkBack ### Jetpack Compose Accessibility ```kotlin import androidx.compose.ui.semantics.* @Composable fun AccessibleButton( onClick: () -> Unit, text: String, enabled: Boolean = true ) { Button( onClick = onClick, enabled = enabled, modifier = Modifier.semantics { contentDescription = text role = Role.Button if (!enabled) { disabled() } } ) { Text(text) } } @Composable fun ProductCard(product: Product) { Card( modifier = Modifier .semantics(mergeDescendants = true) { contentDescription = "${product.name}, ${product.formattedPrice}" customActions = listOf( CustomAccessibilityAction("Add to cart") { addToCart(product) true } ) } .clickable { navigateToDetails(product) } ) { Image( painter = painterResource(product.imageRes), contentDescription = null, // Decorative modifier = Modifier.semantics { invisibleToUser() } ) Text(product.name) Text(product.formattedPrice) } } // Live region for dynamic content @Composable fun Counter() { var count by remember { mutableStateOf(0) } Column { Text( text = "Count: $count", modifier = Modifier.semantics { liveRegion = LiveRegionMode.Polite } ) Button(onClick = { count++ }) { Text("Increment") } } } // Heading levels @Composable fun SectionHeader(title: String, level: Int) { Text( text = title, style = MaterialTheme.typography.headlineMedium, modifier = Modifier.semantics { heading() // Custom heading level (not built-in) testTag = "heading-$level" } ) } ``` ### Android XML Views ```xml