Two mobile developers designing in an iPhone

How to Fix Common iOS Accessibility Issues

iOS provides a lot of accessibility behavior for free, so it’s a great start to making a mobile application accessible. Unfortunately, accessibility is more complicated than the iOS behavior can address, and using only default behavior can actually cause the app to have additional issues.

So, the question is: When should I rely on what iOS provides for free and when should I use additional API to strengthen what’s already available to make my app as accessible as possible?

To help with confusion around this, we’ll cover:

  • What enabling accessibility does
  • When it’s necessary to override default accessibility behavior
  • Some interesting scenarios involving nesting accessibility elements

Working with the Accessibility API in iOS

One of the main (and arguably, most important) accessibility application programming interfaces (APIs) in iOS is the isAccessibilityElement property – or accessibility(hidden) view modifier in SwiftUI. This property is available on any view when developing an application and indicates whether an item can be accessed by VoiceOver.

VoiceOver is the screen reader available on iOS, and it’s the primary assistive technology utilized by blind and low vision users. When isAccessibilityElement is set to true on a view, it means that accessibility is enabled for that view – VoiceOver can generally access this view and read out its contents to the user. If isAccessibilityElement is set to false, accessibility is not enabled for that view; meaning, VoiceOver will treat the view like it’s not there at all.

When is Accessibility Enabled by Default?

Accessibility is enabled for most user interface components and other views that present information (such as text elements, images, buttons, etc).

When an element is focused, VoiceOver will read:

  • the element’s visible text or its accessibilityLabel (its accessible name)
  • its value or its accessibilityValue (its accessible value)
  • certain accessibilityTraits that relate to its accessible role (such as button, link, etc),
  • its accessibilityHint, if hints are enabled in VoiceOver settings and if one exists.

“Username” TextField, filled in with the text “MyUsername.”

In the screenshot above, there is a “Username” TextField, filled in with the text “MyUsername.” The TextField’s name is “Username”, its value is “MyUsername”, and its role is a TextField. In this instance, VoiceOver would read out, “Username, MyUsername, Text field. Double tap to edit.”

When is Accessibility not Enabled by Default?

VoiceOver will completely skip over elements that do not have accessibility enabled. This is the default behavior for UIViews and other layout views (such as StackViews, TableViews, CollectionViews, and ScrollViews).

Table with a list of settings

In the screenshot above, there is a Table with a list of settings.  Instead of focusing on the whole TableView, VoiceOver is instead focused on one of the TableViewCells – specifically the ‘Notifications’ cell, which is currently selected. This gives users more context into what each cell is and the ability to interact with each cell individually.

Overriding Default Accessibility Behavior

As previously mentioned, most views that present information already have accessibility enabled, so you do not need to set the accessibility of every single component in your application. While this is great, you may run into instances where you need to change the accessibility of an element. This can happen if you have:

  • custom/complex controls (such as a control with multiple actions associated with it)
  • purely decorative images
  • visible text describing a control’s purpose

Be very careful when updating the accessibility of elements! Setting this property incorrectly can cause severe accessibility issues—to the point where your app can become unusable to a VoiceOver user.

As a guideline for considering if the accessibility of an element should be overridden, ask yourself: “Does this view present any unique information, or is it repetitive or decorative?”  Keep in mind that all user interface components, when focused by VoiceOver, need to have name, role, and value clearly stated.

Scenarios

Below are some situations when a developer may consider changing the accessibility of an element. Let’s review whether the default accessibility behavior should actually be changed or not.

Scenario #1: Disabled “Submit” Button

A form with a “Submit” button at the bottom, and the “Submit” button is disabled until the form is completely filled out.

The form above has a “Submit” button at the bottom, and the “Submit” button is disabled until the form is completely filled out. Should the “Submit” button have accessibility disabled as well? Well, let’s think back to the guideline listed earlier and consider the following:

Does this disabled “Submit” button present unique information? I would argue that it does. A sighted user that sees a disabled “Submit” button at the bottom of a form can infer that the form is not fully filled out; additional action is required before the button will become available.

When the accessibility of the “Submit” button is disabled, a VoiceOver user would understand that there’s a form that needs to be filled out, but then would be confused about how to actually complete the form to move on to the next screen. And, when the form is completely filled out, the user may be confused when a button suddenly appears that wasn’t there before.

Instead of removing the button from the accessibility hierarchy, UIAccessibilityTraits.notEnabled should be used to portray to VoiceOver users that the “Submit” button is there, but cannot be activated at the moment. Just remember to remove UIAccessibilityTraits.notEnabled once the “Submit” button is available for interaction!

Scenario #2: A Switch with a Visible Label

Accessibility inspector looking at Dark Mode setting

A switch is visually labeled as controlling Dark Mode in an application, and also has its accessibilityLabel set to “Dark Mode.” Should the “Dark Mode” visible text have accessibility enabled?

Does the “Dark Mode” text present unique information? Consider the scenario in which the visible text does have accessibility enabled. When the text is focused, VoiceOver will read “Dark Mode”, then, when the user swipes right to move focus to the switch, it will read “Dark Mode, switch button, off.” Because the switch has its accessibilityLabel set properly, “Dark Mode” would be repeated to a VoiceOver user, so the text does not present unique information and therefore, its accessibility does not need to be enabled.

Best Practice for this Scenario

Accessibility Inspector looking at Dark Mode element

While the above example is WCAG compliant, you may want to also consider that not all VoiceOver users are completely blind; some are partially sighted. In this case, it may be useful to have the VoiceOver focus box contain the visible text and the switch at the same time; this will help partially sighted users understand the structure of your app better. This can be done in a variety of ways, including:

  • overriding the switch’s accessibilityPath
  • making the parent view that holds the switch and its text accessibility enabled, and updating the parent’s accessibilityLabel, accessibilityValue, accessibilityTraits, and accessibilityActivationPoint
  • adding a gesture recognizer to the parent view, making the parent view accessibility enabled, and updating the view’s accessibilityLabel, accessibilityTraits, and accessibilityValue

The best way to implement this (in my opinion) is to have the parent view contain a gesture recognizer because this also provides a larger touch target for those who are using smaller phones or those who have fine motor skill difficulty.

Scenario #3: A Background Image

Should an image that takes up part or most of the background of a screen solely for aesthetic reasons be accessibility enabled?

Does the Image present unique information? Since this image is only for “looks” and does not present any important information to a sighted user, this image should not be accessibility enabled. In fact, presenting purely decorative images to an assistive technology user can be a WCAG issue (1.1.1), so it’s important to discern carefully what counts as important and essential.

Scenario #4: Views Behind a Modal

A modal (or alert) where the views behind it are visible, but cannot be interacted with until the modal is dismissed

A modal (or alert) appears on-screen. The views behind it are visible, but cannot be interacted with until the modal is dismissed. Should the views behind the modal be accessibility enabled?

Do the views behind the modal present unique information? Yes, they do have unique information, but they cannot be interacted with until the modal is dismissed. The views are not decorative, and they are not repeated information.

From this perspective, the views behind a modal should be accessibility enabled, as they present information after the modal is dismissed; however, you do not want a VoiceOver user to be able to interact with the views while the modal is still present. So how should this be remedied?

If the developer has created a custom modal without using a present method, UIAccessibility.Notification.screenChanged may need to be used to inform a VoiceOver user that the screen changed.

Instead of setting every view behind the modal to “accessibility not enabled” (and then re-enabling when the modal is dismissed), the property accessibilityViewIsModal can be used on the root modal view to let VoiceOver know that a modal is present and that views behind the modal should not be accessed at this point in time. It will automatically remove VoiceOver access to these views until the modal is properly dismissed.

Scenario #5: A Shopping Tile

A shopping tile with a sweatshirt, name of product and price

A shopping app contains “tiles”, where you can see an image of the item with its name and price, favorite the item, add it to your cart, and tap on the tile to read a full description, reviews, etc.

If you do not make the tile accessibility enabled, a VoiceOver user may have to swipe hundreds of times just to get to the bottom of the page! In the example above, VoiceOver would focus the image first, followed by the “add to favorites” button, the item’s name (“Exploronic Life”), the “add to cart” button, and finally the price ($26.00). Having to swipe 5 times for every element adds up quickly and can become confusing if there are multiple tiles on one screen. After just a couple of tiles, it may not be clear which “add to favorite” button belongs to which item.

In order to group all of the information as a single item, accessibility should be enabled for the entire tile element. Although grouping all of the tile information together as a single element can make the screen much easier for a VoiceOver user to navigate, there are multiple actions associated with one tile, so it’s important to make sure each action is also available to a VoiceOver user.

Nested Accessibility Elements

One important note about making an element accessibility enabled is that, if it is within a view that is also accessibility enabled, VoiceOver does not have access to the child view. To remedy this, we need to keep related elements together while making multiple actions available to VoiceOver.

Adjustable Accessibility Trait

UIAccessibilityTraits.adjustable can be useful if the user-interface component contains a value that can be incremented and decremented with buttons, like a UIStepper. Consider wrapping the control, its visible label, and its visible value label in a parent view that has accessibility enabled, and adding the adjustable trait to this view.

VoiceOver users can then swipe up or down on this view to update its value, allowing interaction with as few swipes as possible; they can adjust the value quickly and hear how the control’s value is changing in real-time. More information about this trait can be seen in this blog post on iOS accessibility properties.

Custom Accessibility Actions

If the user-interface component does not have a value that can be adjusted, it may be worth looking into custom accessibility actions. In the shopping app tile example above, there were three (3) separate actions. Adding custom accessibility actions to the tile would enable VoiceOver users to quickly and easily interact with the tile without having to swipe through every sub-element.

When using custom accessibility actions, give each action a name that accurately describes the action. This will allow an assistive technology user to more easily understand what the action does.

For those using SwiftUI, you don’t have to worry about this. If you make a “tile” an accessibility element, SwiftUI will automatically convert your individual controls into custom actions that can be usable with VoiceOver.

Conclusion

Now you’re ready to tackle common iOS accessibility issues and make your app more accessible for everyone. Use the accessibility APIs built into iOS to ensure information is making it to all of your application users. Overriding the default accessibility behavior can make your app provide the best experience possible. And finally, using additional accessibility features can help your app create a more usable and enjoyable experience for assistive technology users.

If you have questions about the accessibility of your application, check out our developer tools for Objective-C, Swift and Swift UI, and reach out to us! We’d be happy to help you on your accessibility journey.

photo of Jennifer Korth

About Jennifer Korth

Jennifer Korth is a software engineer who has been working in iOS accessibility at Deque since 2015. While Deque was her introduction to accessibility, one of her projects before graduating from the University of Michigan in 2017 was working closely with C.S. Mott Children’s Hospital to create an accessible, stress-relieving Hololens application for children undergoing cancer treatments and other procedures. In her free time, she loves playing video games with friends, knitting, and having board game nights with her family.