iOS vs. Android Accessibility

Table of Contents


While Google has done a great job improving Android’s Accessibility API, it’s still not nearly as robust as Apple’s iOS Accessibility API. See a comparison of Web Accessibility and WAI-ARIA support in Android and iOS. Learn what ARIA features work in one, both, or neither of these mobile platforms. Learn what’s possible with accessibility development for Native Android & iOS Apps. It's iOS 7 vs. Android 4.4 KitKat in their never ending race towards ultimate accessibility champion!

Slideshow URL


Paul J. Adam

Deque Logo

Accessibility Evangelist at Deque Systems, Inc.

@pauljadam on Twitter


Press the Left/Right Arrow Keys or Page Up/Down to navigate through slides, the Home key takes you home to the table of contents.

This slideshow has been developed with jQuery Mobile to create a universally accessible presentation that will work on any accessibility enabled device. PowerPoint & PDF formats are not universally accessible.

How to Use VoiceOver and TalkBack

How To Use VoiceOver for iOS

voiceover settings screen rotor settings 2 fingers turning rotor

Apple does a great job marketing their accessibility features and including helpful screenshots. At their links below screenshots show VoiceOver speech bubbles explaining how their screen reader works, showing how to use two fingers to turn the VoiceOver Rotor, and other accessibility features for Hearing, Physical, and Learning disabilities.

The iOS 7 User Guide is available in HTML and explains all the VoiceOver settings including how to control the screen reader with different finger combinations, swipes, and taps. It also explains how to use quick navigation gestures and key commands to quickly navigate web pages and test for accessibility using the Rotor or a Keyboard.

iOS 7 User Guide in HTML (Go to Accessibility > VoiceOver)

VoiceOver User Guide Links

Screencast Demo Videos

Below are some screencast videos that show how to use the VoiceOver Practice feature where you can test the different finger combinations and gestures to see what they do without actually activating the command. They also show how to use the Rotor and do basic HTML accessibility testing.

How To Use TalkBack for Android

talkback developer settings screen

The best first step to learn TalkBack is to launch the “Explore by touch” tutorial from TalkBack > Settings for an interactive tutorial where it teaches you how to use TalkBack on your phone or tablet.

More advanced features of TalkBack that you should learn to use include: how to temporarily pause speech, display spoken output on the screen, and learn the shortcut gestures including the global and local context menus.

Native Accessibility API

…supporting accessibility does not impact your ability to innovate and create beautiful iPhone applications.
…thin layer of functionality that does not alter your application’s appearance, or interfere with its main logic.

iOS Native Resources

Android Native Resources



Hide from VoiceOver

Return YES if the receiver should be exposed as an accessibility element.
default == NO
default on UIKit controls == YES
Setting the property to YES will cause the receiver to be visible to assistive applications.
@property(nonatomic) BOOL isAccessibilityElement;

Accessible Name

Returns the localized label that represents the element.
If the element does not display text (an icon for example), this method
should return text that best labels the element. For example: "Play" could be used for
a button that is used to play music. "Play button" should not be used, since there is a trait
that identifies the control is a button.
default == nil
default on UIKit controls == derived from the title
Setting the property will change the label that is returned to the accessibility client.
@property(nonatomic, copy) NSString *accessibilityLabel;

Accessible Description

Returns a localized string that describes the result of performing an action on the element, when the result is non-obvious.
The hint should be a brief phrase.
For example: "Purchases the item." or "Downloads the attachment."
default == nil
Setting the property will change the hint that is returned to the accessibility client.
@property(nonatomic, copy) NSString *accessibilityHint;


Returns a localized string that represents the value of the element, such as the value
of a slider or the text in a text field. Use only when the label of the element
differs from a value. For example: A volume slider has a label of "Volume", but a value of "60%".
default == nil
default on UIKit controls == values for appropriate controls
Setting the property will change the value that is returned to the accessibility client.
@property(nonatomic, copy) NSString *accessibilityValue;

Role, State

Returns a UIAccessibilityTraits mask that is the OR combination of
all accessibility traits that best characterize the element.
See UIAccessibilityConstants.h for a list of traits.
When overriding this method, remember to combine your custom traits
with [super accessibilityTraits].
default == UIAccessibilityTraitNone
default on UIKit controls == traits that best characterize individual controls.
Setting the property will change the traits that are returned to the accessibility client.
@property(nonatomic) UIAccessibilityTraits accessibilityTraits;

Accessibility Traits

Accessibility traits that tell an assistive application how an accessibility element behaves or should be treated.

UIAccessibilityTraits UIAccessibilityTraitNone;
UIAccessibilityTraits UIAccessibilityTraitButton;
UIAccessibilityTraits UIAccessibilityTraitLink;
UIAccessibilityTraits UIAccessibilityTraitSearchField;
UIAccessibilityTraits UIAccessibilityTraitImage;
UIAccessibilityTraits UIAccessibilityTraitSelected;
UIAccessibilityTraits UIAccessibilityTraitPlaysSound;
UIAccessibilityTraits UIAccessibilityTraitKeyboardKey;
UIAccessibilityTraits UIAccessibilityTraitStaticText;
UIAccessibilityTraits UIAccessibilityTraitSummaryElement;
UIAccessibilityTraits UIAccessibilityTraitNotEnabled;
UIAccessibilityTraits UIAccessibilityTraitUpdatesFrequently;
UIAccessibilityTraits UIAccessibilityTraitStartsMediaSession;
UIAccessibilityTraits UIAccessibilityTraitAdjustable;
UIAccessibilityTraits UIAccessibilityTraitAllowsDirectInteraction;
UIAccessibilityTraits UIAccessibilityTraitCausesPageTurn;
UIAccessibilityTraits UIAccessibilityTraitHeader; (Adds element to the Headings Rotor Quick Navigation)

Speak Notifications & Send VoiceOver Focus


This function posts a notification to assistive applications.
Some notifications specify a required or optional argument.
Pass nil for the argument if the notification does not specify otherwise.
See UIAccessibilityConstants.h for a list of notifications.
UIKIT_EXTERN void UIAccessibilityPostNotification(UIAccessibilityNotifications notification, id argument);

Make the VoiceOver Cursor Follow a Curved Vector Path

@property (nonatomic, copy) UIBezierPath *accessibilityPath NS_AVAILABLE_IOS(7_0);

Easy Modal Dialog!

Informs whether the receiving view should be considered modal by accessibility. If YES, then
elements outside this view will be ignored. Only elements inside this view will be exposed.
default == NO
@property(nonatomic) BOOL accessibilityViewIsModal NS_AVAILABLE_IOS(5_0);

Control Reading Order with Grouping

@property(nonatomic) BOOL shouldGroupAccessibilityChildren NS_AVAILABLE_IOS(6_0);

Make Swipes and Custom Gestures Accessible

Implement accessibilityActivate on an element in order to handle the default action.
For example, if a native control requires a swipe gesture, you may implement this method so that a
VoiceOver user will perform a double-tap to activate the item.
If your implementation successfully handles activate, return YES, otherwise return NO.
default == NO
- (BOOL)accessibilityActivate NS_AVAILABLE_IOS(7_0);

Return an array of UIAccessibilityCustomAction objects to make custom actions for an element accessible to an assistive technology.
For example, a photo app might have a view that deletes its corresponding photo in response to a flick gesture.
If the view returns a delete action from this property, VoiceOver and Switch Control users will be able to delete photos without performing the flick gesture.
default == nil
@property (nonatomic, retain) NSArray *accessibilityCustomActions NS_AVAILABLE_IOS(8_0);

Implement VoiceOver's 2-Finger Z "Back Button" Gesture

Implement accessibilityPerformEscape on an element or containing view to exit a modal or hierarchical interface view.
For example, UIPopoverController implements accessibilityPerformEscape on it's root view, so that when
called (as a result of a VoiceOver user action), it dismisses the popover.
If your implementation successfully dismisses the current UI, return YES, otherwise return NO.
default == NO
- (BOOL)accessibilityPerformEscape NS_AVAILABLE_IOS(5_0);

Implement VoiceOver's 2-Finger Double Tap Gesture

Implement accessibilityPerformMagicTap on an element, or the application, in order to provide a context-sensitive action.
For example, a music player can implement this to start and stop playback, or a recording app could start and stop recording.
Return YES to indicate that the action was handled.
default == NO
- (BOOL)accessibilityPerformMagicTap NS_AVAILABLE_IOS(6_0);

AT Detection

Assistive Technology

Use UIAccessibilityIsVoiceOverRunning() to determine if VoiceOver is running.
Listen for UIAccessibilityVoiceOverStatusChanged to know when VoiceOver starts or stops.
UIKIT_EXTERN BOOL UIAccessibilityIsVoiceOverRunning() NS_AVAILABLE_IOS(4_0);
UIKIT_EXTERN NSString *const UIAccessibilityVoiceOverStatusChanged NS_AVAILABLE_IOS(4_0);

// Returns whether system audio is mixed down from stereo to mono.
UIKIT_EXTERN BOOL UIAccessibilityIsMonoAudioEnabled() NS_AVAILABLE_IOS(5_0);
UIKIT_EXTERN NSString *const UIAccessibilityMonoAudioStatusDidChangeNotification NS_AVAILABLE_IOS(5_0);

// Returns whether the system preference for closed captioning is enabled.
UIKIT_EXTERN BOOL UIAccessibilityIsClosedCaptioningEnabled() NS_AVAILABLE_IOS(5_0);
UIKIT_EXTERN NSString *const UIAccessibilityClosedCaptioningStatusDidChangeNotification NS_AVAILABLE_IOS(5_0);

// Returns whether the system preference for invert colors is enabled.
UIKIT_EXTERN BOOL UIAccessibilityIsInvertColorsEnabled() NS_AVAILABLE_IOS(6_0);
UIKIT_EXTERN NSString *const UIAccessibilityInvertColorsStatusDidChangeNotification NS_AVAILABLE_IOS(6_0);

// Returns whether the app is running under Guided Access mode.
UIKIT_EXTERN BOOL UIAccessibilityIsGuidedAccessEnabled() NS_AVAILABLE_IOS(6_0);
UIKIT_EXTERN NSString *const UIAccessibilityGuidedAccessStatusDidChangeNotification NS_AVAILABLE_IOS(6_0);

// Returns whether the system preference for bold text is enabled
UIKIT_EXTERN BOOL UIAccessibilityIsBoldTextEnabled() NS_AVAILABLE_IOS(8_0);
UIKIT_EXTERN NSString *const UIAccessibilityBoldTextStatusDidChangeNotification NS_AVAILABLE_IOS(8_0);

// Returns whether the system preference for grayscale is enabled
UIKIT_EXTERN BOOL UIAccessibilityIsGrayscaleEnabled() NS_AVAILABLE_IOS(8_0);
UIKIT_EXTERN NSString *const UIAccessibilityGrayscaleStatusDidChangeNotification NS_AVAILABLE_IOS(8_0);

// Returns whether the system preference for reduce transparency is enabled
UIKIT_EXTERN BOOL UIAccessibilityIsReduceTransparencyEnabled() NS_AVAILABLE_IOS(8_0);
UIKIT_EXTERN NSString *const UIAccessibilityReduceTransparencyStatusDidChangeNotification NS_AVAILABLE_IOS(8_0);

// Returns whether the system preference for reduce motion is enabled
UIKIT_EXTERN BOOL UIAccessibilityIsReduceMotionEnabled() NS_AVAILABLE_IOS(8_0);
UIKIT_EXTERN NSString *const UIAccessibilityReduceMotionStatusDidChangeNotification NS_AVAILABLE_IOS(8_0);

// Returns whether the system preference for darker colors is enabled
UIKIT_EXTERN BOOL UIAccessibilityDarkerSystemColorsEnabled() NS_AVAILABLE_IOS(8_0);
UIKIT_EXTERN NSString *const UIAccessibilityDarkerSystemColorsStatusDidChangeNotification NS_AVAILABLE_IOS(8_0);


Develop - API Guides - Accessibility - Making Applications Accessible

Labeling UI Elements


Note: For EditText fields, provide an android:hint attribute instead of a content description, to help users understand what content is expected when the text field is empty. When the field is filled, TalkBack reads the entered content to the user, instead of the hint text.

contentDescription on an EditText control is only read before text is typed into the field, once the field is emptied the contentDescription is no longer read. This is a reason why a hint is a better option. Even though both disappear as the accessible name once text is typed into the field the hint comes back into view when the field is emptied and it will be read again by TalkBack, not the case for contentDescription on EditText controls.

Develop - Training - Implementing Accessibility - Developing Accessible Applications | Android Developers

Add Content Descriptions

Static Labels Use XML layout android:contentDescription

Labels that won't change while using the app (such as "Next" or "Purchase") can be added via the XML layout by setting a UI element's android:contentDescription attribute:


Dynamic Labels Use runtime method .setContentDescription()

Base the content description on some context, such as the state of a toggle button, or a piece of selectable data like a list item. To edit the content description at runtime, use the setContentDescription() method:

String contentDescription = "Select " + strValues[position];

Don't overdo your labels

Avoid the web-developer pitfall of labelling everything with useless information. For instance, don't set an application icon's content description to "app icon". That just increases the noise a user needs to navigate in order to pull useful information from your interface.

Newer <TextView> android:labelFor Property

</TextView >

Android labelFor warning fix

Design for Focus Navigation (Directional D-Pad, & Keyboard)

Enabling view focus


If a view is not focusable by default, you can make it focusable in your layout file by setting the android:focusable attribute to true or by calling the its setFocusable() method.

Controlling focus order

Each UI control has 4 attributes, android:nextFocusUp, android:nextFocusDown, android:nextFocusLeft, and android:nextFocusRight, which you can use to designate the next view to receive focus when the user navigates in that direction.

Note: You can modify the focus order of user interface components at runtime, using methods such as setNextFocusDownId() and setNextFocusRightId().

Common Questions/Issues with Android Native Accessibility

How do I hide an element from TalkBack so that it does not receive focus and no accessible name is announced?


noHideDescendants - The view is NOT important for accessibility, nor are any of its descendant views.


Stop images from being focusable with TalkBack by setting android:focusable=“false” or android:importantForAccessibility=“no”(which overrides :focusable on an ImageView)

How do I send TalkBack focus to an element so that it's announced?


Are there automated accessibility testing tools for Android?

Android Lint

Android Accessibility Testing and Fixing in 30 seconds

Deque recently introduced a WorldSpace Xcode plugin to do automated accessibility testing for iOS!

How to I send an announcement for TalkBack to speak to the user like when a screen changes?

view.announceForAccessibility("Hello TalkBack World");

Resources from Google

Limitations of Android A11y API vs. iOS

Android's Weak Accessibility API leaves it light years behind iOS/VoiceOver

iOS accessibility API options

There are no traits, no hints on all elements, etc. If you want a UI element to be spoken as a "button" to TalkBack then you must use a button or image button element since there is no button trait(role).

No accessibilityViewIsModal like iOS, the API is just not nearly as robust!

EditText elements can't have both a contentDescription and a hint! And as soon as you type some text the hint or contentDescription is NOT spoken.

Android handles links embedded in a textview by using an earcon ding but no role/trait to indicate the separate elements. They're not separately focusable!

Opening local context menu gives ability to activate separate links but this is not very obvious or documented much.

local context menu links

TalkBack users do not hear if something is actionable unless it's a button or input element.

Tab controls do not indicate a tab role or a selected state.

Good blog posts on Android's "faux" accessibility:

Web Accessibility Support on Mobile

Description, The contract model with accessibility APIs


Not all old school HTML accessibility methods like Fieldset & Legend or the <td> headers attribute work on all mobile devices like iOS.

Quick Navigation by Semantic HTML Elements with Screen Readers

Semantic HTML Mobile Accessibility Support

Android Browser Options

Android users can download multiple browsers with different rendering engines like Chrome and Firefox. The different Android browsers have different levels of accessibility and stability bugs. Firefox is actually the most accessible browser for Android. Accessibility testing differs with TalkBack on Chrome vs. Firefox.

Mobile Safari for iOS

While iOS users can download different browsers like Chrome, these 3rd-party browsers are actually running Apple's Webkit rendering engine underneath the covers so there is no differences in accessibility of HTML on Mobile Safari vs Chrome for iOS.

Language Detection & TTS

WCAG requires the language of the document bet set, e.g. lang="en". Setting the document language to a value supported by the screen reader will cause the synthesizer to automatically switch to the correct language and speak an accurate pronunciation of the words in the correct dialect.


In this Live Demo, with VoiceOver set to the default language in the Rotor, reading this German news story VO will automatically switch from US English to German: Ex-Verfassungsrichter: Staat muss vor NSA-Ausspähung schützen

Languages with JAWS and MAGic on the Internet

The TalkBack screen reader for Android (Chrome or Firefox) does not support Language Detection, switching synthesizer based on lang attribute.

CSS3 Speech Verbosity

The CSS Speech Module W3C specification offers interesting properties that work only with VoiceOver for iOS to control how VoiceOver speaks text strings.

For example, in the below code snippet with {speak: literal-punctuation;} we can tell the VoiceOver screen reader (for iOS only) to speak all special characters including the asterisks, brackets, colons, semicolons, at symbols, and quotation marks. If this CSS property is not used then by default only the * and @ are read out loud by VoiceOver.

UIImageView *view = [[UIImageView alloc] initWithImage:image]; view.accessibilityLabel = @"Apple Logo";

.address, .phone, .zip {speak: digits;}
code {speak: literal-punctuation;}


CSS3 Speech

Text To Speech with the Web Speech API

Live HTML Demo Talking Webpage No Screen Reader Used

Browser Options

Mobile Safari is your ONLY option on iOS. Any browsers like Chrome for iOS run as a skin on top of Apple's accessible browser.

Android Browsers


Chrome is super buggy which is sad as it's the default browser app installed on Android. Chrome does this weird thing where as soon as I swipe to a text input the accessible name is NOT spoken and instead the keyboard appears automatically and TalkBack quickly interrupts yo to say "Showing text keyboard web view"


New features for TalkBack users in Firefox for Android 24

What’s New for TalkBack users in Firefox 25 for Android

First round of accessibility support for Android in mobile Firefox | Marco’s accessibility blog
Quick Navigation keys now in nightly builds of Firefox native for Android | Marco’s accessibility blog

List of quick navigation keys for accessible Firefox for Android
Key Description
a Moves to next named anchor
b Moves to next button
c Moves to next combobox or listbox
e Moves to next text entry or password field
f Moves to next form field (button, combobox, text entry, radio button, slider, checkbox)
g Moves to next graphic
h Moves to next heading of any level
i Moves to next item in an unordered, ordered or definition list
k Moves to next hyperlink
l Moves to next unordered, ordered or definition list
p Moves to next page tab (in ARIA-enabled web apps)
r Moves to next radio button
s Moves to next separator
t Moves to next data table
x Moves to next checkbox

headings navigationlandmarks quick nav

How to use TalkBack support in Firefox for Android for accessibility


landmarks rotor

iOS and Android have excellent support for WAI-ARIA, even better than some desktop browsers and screen readers.

WAI-ARIA Support Matrix

Live Demos

SVG (Scalable Vector Graphics) Using ARIA for Semantics




Live Demos

Labels vs. Placeholders

Placeholder always fails contrast by default :(

placeholder shown failing color contrast

       ::-webkit-input-placeholder {
 color: #666;
:-moz-placeholder { /* Firefox 18- */
       color: #666; 
::-moz-placeholder {  /* Firefox 19+ */
       color: #666; 
:-ms-input-placeholder { 
       color: #666; 



HTML5 WebVTT Captions

yellow custom textandroid chrome captions

HTML5 Captioned Video Example

		  <video id="demo-video" controls>
           <source src="VoiceOverPracticeFeatureDemoiniOS7.mp4" type="video/mp4">
           <source src="VoiceOverPracticeFeatureDemoiniOS7.webm" type="video/webm">
         <track label="English Captions" srclang="en" kind="captions" src="captions.vtt" type="text/vtt" default></track>
           Your browser does not support the HTML5 &lt;video&gt; tag.

Custom Video Controls

It is necessary to create custom HTML5 video player controls because most native HTML5 video implementations have not been made screen reader accessible, for example HTML5 video elements in iOS are skipped right over when using VoiceOver and doing linear, swipe navigation. The <video> element is actually at the bottom of the DOM so the user has to swipe through the entire webpage before arriving on the video element. Once a VO iOS user does land on the video element it does not actually read a unique accessible name for the element and VoiceOver simply speaks "Video" when focused on the container and "Play, button" when focused on the large native play button.

YouTube for iOS

vimeo player captions

Introducing the New Vimeo Player

Vimeo recently announced their new accessible, HTML5 video player that uses the user-customizable WebVTT closed captions and it worked very well in my testing.

Android 4.4 KitKat Closed Captions API

System-wide settings for closed captioning

Android 4.4 now supports a better accessibility experience across apps by adding system-wide preferences for Closed Captioning. Users can go to Settings > Accessibility > Captions to set global captioning preferences, such as whether to show captions and what language, text size, and text style to use.

HTML5 Captioned Video Example

YouTube for Android

CPC Closed Captioning Demo Video on YouTube

Audio Descriptions Spoken to Blind Users via WAI-ARIA Live Regions

talkback speaking live region

Comparing A11y of Popular Apps on Android vs. iOS





map view not accessible on android the + - buttons and map pins have no accessible names

map pin detail tooltips not accessible at all

Only the list view is accessible


The Map view pins are accessible and indicate their selected state. This is likely a limitation of google's map view API.

The Weather Channel



Pros & Cons of Android/TalkBack vs. iOS/VoiceOver

iOS Pros

iOS Cons

Android Pros

Android Cons

Android's Open App Eco System

Best Android Keyboards for Limited Dexterity (or anyone)

Best Alternative Android Keyboards for the rest of us with fat fingers, poor dexterity, arthritis, repetitive stress injuries, paralysis, and other finger/hand limitations.

Learn More about Paul...





Mobile Accessibility 101 Webinar