Chapters

Hide chapters

Real-World iOS by Tutorials

First Edition · iOS 15 · Swift 5.5 · Xcode 13

Before You Begin

Section 0: 4 chapters
Show chapters Hide chapters

10. Implementing Accessibility
Written by Josh Steele

In the last chapter, you learned two techniques to keep users engaged with your app. Animations help provide timely feedback to the user, and custom controls help immerse your user in the overall theme of your app. Both are part of Apple’s HIG, or Human Interface Guidelines for iOS.

Accessibility is a broader technology that applies to all the Apple operating systems and has a dedicated section under the HIG website.

In this chapter, you’ll learn how the Accessibility technologies in iOS help make implementing those guidelines available to more users.

But what exactly is Accessibility, and why should you use it in your app?

Why design for accessibility?

Here are two statistics that may surprise you:

  1. According to the CDC, one in four adults in the United States has some type of disability.
  2. Current estimates state that one in 12, or 8%, men are color blind.

If that first number surprises you, you’re not alone. Many people have invisible disabilities, such as color blindness.

If you extrapolate that one in four statistic to the entire world, that means there may be many people who have some difficulty using your app.

When you use Accessibility technologies, your app:

  1. Becomes more accessible: This one may seem obvious since it’s right there in the name. A larger number of people can download and use your app.
  2. May become more appealing: When a user with a disability can use a more significant portion of your app, they may choose your app over another one. Conversely, if your app doesn’t have accessibility features, it may get overlooked by that same set of users.

Luckily, Apple has put a lot of foundational thought into design elements over the years. There were some hits and misses along the way. Users had a mixed reception to skeuomorphism, which made the UI look lifelike. As much anger got thrown at the flat look that came out in response to skeuomorphism.

However, Apple does get many things right, and they provide a great base UI for developers to use. They also describe those in, you guessed it, the Apple HIG.

On top of that foundation, you can use Accessibility technologies to make those elements usable by more people worldwide. Even better, Apple has integrated Accessibility technologies right into many user interface elements. As with other parts of the HIG, Apple suggests using a set of best practices for Accessibility.

Best practices in the Apple Human Interface Guidelines

Each iOS user interface component has its own best practices for design and accessibility. Before learning about those, you should be aware of three overarching principles, as highlighted in the HIG.

Designing for accessibility

Software engineering principles place design early on in the development process. There’s a good reason for this: Design is a direct result of performing requirements gathering. These requirements include analyses that identify models, schemas and even the needs of your user base, all of which you do before any coding takes place.

Typical design processes focus on the usability of your user interface, including making sure the user can accomplish various tasks within your app. When you incorporate accessibility into your design process, your goal is to make your app usable for not only people with disabilities but as many people as possible. The HIG highlights two focus areas here:

  • Simplicity: Familiar interactions that keep tasks simple and straightforward to perform.
  • Perceivability: Users can engage with your app with several of their senses, including sight, hearing and touch.

You’ll see both of these areas pop up from time to time in this chapter.

Supporting adaptability

One of the best things about using Apple’s built-in user interface elements is that you automatically get the accessibility support for those elements. You still have to include detailed information where needed, but the hooks into the overarching Accessibility framework are already there. Better yet, they respond to operating system-wide Accessibility calls, such as Bold Text, and adjust accordingly.

You can also easily add accessibility features to your custom user interface elements. This lets tools such as VoiceOver recognize that element and present it to the user. You’ll learn about VoiceOver later in this chapter.

Test, test, test and did we mention test?

Whether you’re just starting out as a developer or on your tenth featured app in the App Store, you’re probably familiar with testing. Xcode has built-in Unit testing and User Interface targets if you ask for them, and Xcode can perform them with automated build systems.

When you integrate Accessibility technologies into your app, you have to go a step further. Once you turn accessibility features on, you can explore alternative methods users can use to interact with your app. You’ll discover areas that need improvement from an accessibility standpoint and may even find areas to improve your app’s overall user experience.

You should run each use case for your app with an accessibility feature, such as VoiceOver, turned on. You’ll see how the app behaves and if a user can accomplish that use case easily. Accessibility Inspector in Xcode can help you with this.

You’ll learn more about VoiceOver and Accessibility Inspector later in this chapter.

With these guidelines in place, it’s time to go deep into some key user interface elements in iOS. There’s a mix of general design guidelines and accessibility technologies in each area. So, time to get started!

Text

Whatever language you use, your app uses text to convey important information to your users. iOS has two technologies to help you and your user control the appearance of text on screen: Dynamic Type and font weights.

Dynamic Type

In iOS 7, Apple added Dynamic Type to the iOS SDK. Dynamic Type has a few interesting features:

  • Adjustable text size: Users can enable Dynamic Type to adjust the on-screen text size system-wide. Those who want to see more text on screen can make the font smaller. Others, with vision difficulties, for example, can increase the font size to make the text more accessible to them.
  • Apps must add support: Although the toggle for Dynamic Type is system-wide, only systems that use Dynamic Type fonts will respond to that call from the OS.

You can enable Dynamic Type by going into the Accessibility settings and turning it on. Under Settings in iOS, the Accessibility settings include a Display & Text Size category of settings. Within that group of settings, you can toggle on Larger Text and choose the text size you prefer.

The Dynamic Type size selection screen in iOS 15.
The Dynamic Type size selection screen in iOS 15.

You can also enable Dynamic Type in the Preview Canvas by using the .environment modifier on your preview:

ContentView()
  .environment(\.sizeCategory, .extraLarge)

You use the \.sizeCategory key path to access the Dynamic Type size for the preview. The value .extraLarge sets the text size.

You still need to enable Dynamic Type support in your app before taking advantage of this feature. Here’s how the text in PetSave looks without Dynamic Type support, specifically, the PetRankingView view:

PetRankingView without Dynamic Type.
PetRankingView without Dynamic Type.

You’ve seen this screen if you’ve followed along in building the project to this point. PetSave uses several built-in iOS technologies, including the Text SwiftUI widget for displaying text in the app. By default, this widget uses a Dynamic Type font.

The starter project also uses font modifiers on some of the Text views to change to other font sizes such as .caption or .headline. This is a great example of taking advantage of the built-in features iOS provides. You can see this in action in the Preview Canvas.

Open the starter project and go to PetSave/Core/views and open PetRanking.swift.

Update the previews block at the bottom of the file:

struct PetRankingView_Previews: PreviewProvider {
  static var previews: some View {
    if let animal = CoreDataHelper.getTestAnimalEntity() {
      Group {
        PetRankingView(animal: animal)
          .padding()
          .previewLayout(.sizeThatFits)
          .environment(\.sizeCategory, .extraSmall)
          .previewDisplayName("Extra-Small")

        PetRankingView(animal: animal)
          .padding()
          .previewLayout(.sizeThatFits)
          .previewDisplayName("Regular")

        PetRankingView(animal: animal)
          .padding()
          .previewLayout(.sizeThatFits)
          .environment(\.sizeCategory, .extraLarge)
          .previewDisplayName("Extra-Large")
      }
    }
  }
}

This code adds a few more previews to the canvas to show the .extraSmall and .extraExtraLarge Dynamic Type sizes.

Click resume on the preview canvas, if necessary, and you’ll see the various font sizes:

Animals Near You with Dynamic Type.
Animals Near You with Dynamic Type.

There are some things you need to keep in mind when using Dynamic Type in your app:

  • Avoid truncation: As your user increases the Dynamic Type size, the text size increases, but the device size doesn’t increase along with it. So your text runs the risk of becoming truncated if it becomes too large. Using the numberOfLines property in a label lets the system automatically grow the label vertically.
  • Adjust layout if needed: If your user interface is complex, larger text sizes may make several regions of the interface hard to read. You may need to adjust the layout of your user interface to larger text sizes. For example, shifting horizontal layouts, such as HStack, to a VStack can keep certain elements from getting truncated.
  • SF Symbols is dynamic: Text isn’t the only thing that responds to Dynamic Type. SF Symbols can grow and shrink right along with the text on screen, keeping the interface uniform. This is another reason to use built-in technologies such as SF Symbols!

Font weights

Your font choice is important when you design your app’s user interface. Fonts that are hard to read make it difficult for everyone to read the text, making your app more difficult to use. Once you choose a font for your app, there are some best practices to keep in mind:

  • Use regular or heavy fonts: For the best user experience, avoid thin or light fonts and use regular or heavy weighted fonts. These fonts are easier to read.
  • Ensure bold text is readable: Users can activate bold text under the Display & Text Size section of the Accessibility preferences pane. Ensure that text in your app looks good with this feature enabled.

VoiceOver

VoiceOver is a built-in screen reader in iOS. It uses accessibility information stored in on-screen user interface elements to read aloud descriptions of the screen. With it, you can:

  • Speak the name of elements: You can drag your finger across the screen to have VoiceOver read the names of the item you’re currently touching.
  • Use VoiceOver gestures to interact: You can use special VoiceOver gestures to interact with the elements since the main interaction with the elements causes VoiceOver to read the names.
  • Adjust speaking rate and pitch: You can adjust the rate and pitch of the voice that VoiceOver uses to your liking.

Later in this chapter, you’ll learn how to ensure your app has the information VoiceOver needs. You’ll also learn how to preview what VoiceOver will say for each element by using the Accessibility Inspector.

Navigation

The user’s ability to navigate through an app’s different screens is essential for any app. Navigation becomes more important when considering accessibility.

Here are some best practices to follow:

  • Ensure navigation is possible: Make sure VoiceOver can navigate to every element.
  • Provide alternate text: By adding alternative text labels to user interface elements, you ensure VoiceOver provides users a more detailed description of that element. Both custom elements and system-provided controls support alternative text labels.
  • Support the VoiceOver rotor: The VoiceOver rotor lets a user navigate between various section types of a document or webpage. Make these elements visible to the rotor so VoiceOver can present them to the user.

Color and contrast

How you use color in your app can convey a great deal of information to your user. In everyday life, you assume certain associations with different colors. For example, red means stop and green means go.

If you recall the statistic from the beginning of the chapter, estimates state that roughly 8% of all men have a red-green color blindness disability, meaning they have difficulty telling red and green pigments apart. You may be thinking, “But what about traffic lights?”. Good question. Luckily, there’s a paradigm for this:

Depiction of a railroad traffic light.
Depiction of a railroad traffic light.

It’s a worldwide paradigm that vertical traffic lights have red at the top, green at the bottom and amber in the middle.

Unfortunately, there aren’t worldwide paradigms for iOS development. However, there are some best practices:

  • Use glyphs: You can use recognizable glyphs, such as those from SF Symbols, in addition to the colors to convey information.
  • Use text labels: Even without color, text is important, and you can still use it to convey information.
  • Use standard colors: Be sure to take advantage of iOS’s built-in features. System colors respond properly to accessibility features such as Invert Colors.
  • Respond to Invert Colors: Speaking of Invert Colors, if you have custom colorings, make sure your app responds appropriately when your user enabled Invert Colors.

The contrast between colors is another powerful tool to make parts of your user interface pop. If a foreground object and a background object are too similar in color, it can be hard to distinguish them.

Go to AnimalDetails/views and open AnimalDetailCard.swift:

Poor contrast ratio.
Poor contrast ratio.

The green-on-green and blue-on-blue color combinations don’t provide the best contrast. Similar shades on top of each other don’t stand out well.

The Institute for Disability Research, Policy and Practice at Utah State University has an online contrast checker, so you can look up contrast values if you know the colors’ hex values. The current guidelines, which Apple also recommends in the HIG, are:

  • Normal Text (<= 17 pt): Ensure a contrast ratio of 4.5:1.
  • Large Text (> 17 pt): Ensure a contrast ratio of 3:1.

Use the calculator above to check your ratios and ensure your elements pop on the screen. The contrast ratio for the green block is 1.88:1, which is less than the requirements above. A proper contrast ratio can turn the above image into this one:

Great contrast ratio.
Great contrast ratio.

The text stands out a bit more now with the greater contrast ratio. You should check all areas of your app where contrast ratio issues may arise. Fortunately, Xcode has Accessibility Inspector to help accomplish that.

Using the Accessibility Inspector

The best way to learn about accessibility features in iOS is to apply them to an app. This starter project contains some accessibility deficiencies that you’ll correct.

Run and build the starter project. Then, in the Xcode menu, go to Xcode -> Open Developer Tool -> Accessibility Inspector.

The Accessibility Inspector menu item in Xcode.
The Accessibility Inspector menu item in Xcode.

Put the Simulator and Accessibility Inspector window side by side. In the upper left-hand corner, select the simulator as the item to inspect, then click target selector at the top right and click over the animals’ list. You’ll see something like this:

The Accessibility Inspector and Simulator.
The Accessibility Inspector and Simulator.

The Accessibility Inspector has three areas you can use to help test your app, the first of which is the Inspection Tool.

Inspection tool

Inspection Tool is the default tool when the Accessibility Inspector launches. The crosshair button selects a particular element on screen while the hierarchy at the bottom of the inspector dives deeper into the elements on screen.

With the first row selected, scroll down in the hierarchy and choose the first element in the row. Then click the arrow to the right of the element to dive in:

Details from inspecting an element in the on screen view.
Details from inspecting an element in the on screen view.

The Basic section at the top lists some information about the element under inspection. It’s static text and lists the text of the Text view in the Label section.

That label comes into play when using VoiceOver. Tap the Speak button, and you’ll hear what VoiceOver would say for this element:

The speak button allows you to hear what VoiceOver would say for this element.
The speak button allows you to hear what VoiceOver would say for this element.

Speaking the text of the Text element is useful. But, it’s not informative to someone who can’t see the screen and depends on the descriptions from VoiceOver to help them. Later on, you’ll see how to improve this label to give VoiceOver more informative content.

If you have a complex app, it can be time-consuming to go through each and every element and inspect it by hand. Fortunately, the Audit Tool can do that for you.

Audit tool

You can use the Audit Tool to generate a report of possible Accessibility violations from the user interface elements currently on screen.

Select the Audit Tool, the middle button in the upper right-hand corner of the Accessibility Inspector.

Audit Tool icon.
Audit Tool icon.

Run an audit with the Animals Near You view showing:

Results of an audit of the Animals Near You screen.
Results of an audit of the Animals Near You screen.

There are several contrast-related warnings. Fix these by using a darker color for the text to make it stand out from the background.

Go to PetSave/Core/AnimalDetails/views/ and open AnimalDetailCard.swift. Add the following extension to Color:

extension Color {
  func darken(_ amount: Double) -> Color {
    let uiColor = UIColor(self)
    var red: CGFloat = 0
    var green: CGFloat = 0
    var blue: CGFloat = 0
    var alpha: CGFloat = 0
    uiColor.getRed(&red, green: &green, blue: &blue, alpha: &alpha)
    let darkenedUIColor =
      UIColor(
        red: min(red - amount / 100, 1.0),
        green: min(green - amount / 100, 1.0),
        blue: min(blue - amount / 100, 1.0),
        alpha: 1.0)
    return Color(darkenedUIColor)
  }
}

This method extracts the color’s current RGB values and darkens it by the passed in amount. Color has a limited API, so the code converts Color to a UIColor to help get the component values.

In the foreground modifier later in the file, use a darker color:

.foregroundColor(color.darken(40.0))

This will take the passed in color and darken it by 40%. Use this darker color in the AnimalAttributes view modifier.

Open AnimalAttributesCard.swift and update the modifier:

struct AnimalAttributesCard: ViewModifier {
  let color: Color
  func body(content: Content) -> some View {
    content
      .padding(4)
      .background(color.opacity(0.2))
      .cornerRadius(8)
      .foregroundColor(color.darken(+40))
      .font(.subheadline)
  }
}

Again, the foreground color’s darkness increases by 40% to increase the contrast ratio.

You can address the Potentially inaccessible text warnings in the audit report by including .accessibility modifiers on your Text fields. For example, in AnimalContactLink.swift, add a modifier to the title’s Text element:

Text(title)
  .font(.callout)
  .accessibility(label: Text("The contact information for this pet: " + title))

Adding this label also helps with the VoiceOver issue from earlier. VoiceOver now has a more complete label to read aloud and gives the user the on screen information and the context in which it exists.

Note: Go and check AnimalRow.swift, the Text views already have accessibility(label:) in place.

Update the other Text elements in the app. With these corrections in place, build and rerun the app. Then rerun the audit:

The updated audit result.
The updated audit result.

The report shows that many of the contrast warnings are gone, but not all of them. These are from native iOS elements, specifically the disclosure indicator, which means Apple has some work to do to make their own elements accessible!

The Potentially inaccessible text warnings are still in this report, even though you added accessibility labels to the Text views. This seems to be a bug in Accessibility Inspector, possibly because it doesn’t completely understand SwiftUI.

The Accessibility Inspector is a powerful tool, but it would be nice to have tools built right into Xcode that give you more insight into the accessibility of your UI elements. Fortunately, Xcode 13 and macOS Monterey put such a tool into developers’ hands.

The Xcode accessibility inspector

It’s time for a quick detour from the Accessibility Inspector app to the similarly named Accessibility Inspector property pane in Xcode:

The Accessibility Inspector property pane in Xcode 13.
The Accessibility Inspector property pane in Xcode 13.

The image above shows the AnimalRow view accessibility information. To see this in action, open AnimalRow.swift and click AnimalRow(animal: animal) in the previews struct at the bottom of the file. Then click the accessibility tab: It’s the second icon from the right in the Inspectors tab, showing a person inside a circle.

The Accessibility Inspector property pane now shows all of the relevant accessibility elements within AnimalRow, which as a reminder looks like this:

The AnimalRow view in the Petsave app.
The AnimalRow view in the Petsave app.

The Accessibility Inspector pane shows the accessibility information for each element. It also lists the elements in the order in which VoiceOver would read them out.

When VoiceOver reads this view, it says: “Fiona, Pit Bull Terrier Dog, Hi, I am Fiona. I am a 9-month-old beautiful sweet pittie girl. I love to play with my. Young. Female. Button.”

That’s a lot for someone to deal with. SwiftUI has some new accessibility modifiers that can help developers provide important information first and give the user the choice to reveal more content.

You’ll simplify the VoiceOver details in three steps:

  1. Combine accessibility: Treat the entire row as one unit from an accessibility perspective.
  2. Hide existing labels: Hide some accessibility labels so that only certain ones show by default.
  3. Add custom fields: Add the remaining accessibility labels as custom accessibility entries.

First, combine the accessibility entries of the internal views of the HStack by using a modifier:

HStack {
//...
}
.accessibilityElement(children: .combine)

Make sure you add this modifier to the topmost HStack, the one that contains all the children views.

This code combines the accessibility entries of the children into one listing for the container. This modifier changes the entry for the HStack in the accessibility inspector to look like this:

The AnimalRow view in the Petsave app.
The AnimalRow view in the Petsave app.

While that’s better, it’s still pretty verbose. Hide some accessibility labels that shouldn’t be there by default.

Except for the name and gender, add the following modifier to the Text views throughout this view:

.accessibilityHidden(true)

Here, you disable VoiceOver’s ability to read these entries. Now the accessibility inspector looks like this:

Some accessibility labels are now hidden.
Some accessibility labels are now hidden.

Much more to the point! You still need to give the user the chance to access the other information. Add the following modifiers after accessibilityElement(children:):

.accessibilityCustomContent("Age", animal.age.rawValue,
  importance: .high)
.accessibilityCustomContent("Breed", animal.breed)
.accessibilityCustomContent("Type", animalType)
.accessibilityCustomContent("Description", animalDescription)

The Accessibility Inspector now shows this:

Now the HStack has custom accessibility fields
Now the HStack has custom accessibility fields

Note: It looks like Xcode 13 may have a bug that keeps it from displaying more than three custom content elements in the Accessibility Inspector, as reflected in the screenshot above. All the fields are properly detected when run on a device, however!

To properly test this, you need to deploy the app to a device. Then:

  1. Enable VoiceOver: Enable VoiceOver in Settings via the Accessibility->VoiceOver menu item.
  2. Go to PetSave: Ask Siri to Open PetSave.
  3. Select a row: In the Animals Near You view, select a row. VoiceOver will speak the important parts and tell you there is more content.
  4. Activate the VoiceOver Rotor: Make a twist motion on the screen with two fingers. The VoiceOver rotor will appear. Keep twisting until it says More Content.
  5. Flick up to hear more: Once you choose More Content, lift your fingers. Then immediately flick up to hear the first custom accessibility element. Continue flicking to hear more content.
  6. Turn off VoiceOver: When you’re done, ask Siri to Open Settings. Turn off VoiceOver from there with a double-tap the switch.

Accessibility settings

Once you’ve made corrections from the audit, you still have work ahead. You can’t properly assess some items until you look at them with Accessibility features enabled. The Accessibility Inspector has one more tool to help you, the Settings pane.

The Setting pane lets you toggle settings on and off from the Accessibility Inspector instead of having to go into the Simulator settings:

The Accessibility Inspector Settings pane.
The Accessibility Inspector Settings pane.

Using these settings depends on your app and the features it supports. Take advantage of the accessibility of these settings and use them to test your app thoroughly!

Key points

  • Using Accessibility technologies in your app makes your app more accessible to a larger audience.
  • Incorporate accessibility early in the design of your app.
  • Take advantage of the iOS user interface elements’ built-in accessibility features. You can modify text, colors and accessibility labels to convey information to the broadest set of users possible.
  • Testing is vital when working with accessibility technologies. You may not actively use these features in your day-to-day app use. Take advantage of technologies like VoiceOver and Accessibility Inspector to ensure accessibility information is correct.

Where to go from here?

Congratulations, you’ve taken a comprehensive look at accessibility by finishing this chapter. Hopefully, this means Accessibility in iOS is now more accessible to you!

For a deeper look at implementing Accessibility in your app, there are several tutorials available at raywenderlich.com.

Apple’s HIG, or Human Interface Guidelines for iOS has a specific section that covers Accessibility, which supplements the information presented in this chapter.

There are also several sessions from WWDC 2021 that are worth looking at in regards to accessibility and the new features introduced in iOS 15.

There’s one more area to cover in this section of the book. In the next chapter, you’ll learn some ways to customize your app’s look and feel to give it a unique identity.

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.
© 2026 Kodeco Inc.