Preparing your App for VoiceOver: Accessibility Traits

Preparing your App for VoiceOver: Accessibility Traits

Ensure the interface elements of your app communicate their function properly to assistive technologies

When we structure the user interface we use different components for different purposes.

One way to guarantee that our user interfaces are truly accessible is to respect the WCAG (Web Content Accessibility Guidelines). Among the guidelines we should comply with are:

Guideline 1.1 Text Alternatives
Provide text alternatives for any non-text content so that it can be changed into other forms people need, such as large print, braille, speech, symbols or simpler language.
Guideline 1.3 Adaptable
Create content that can be presented in different ways (for example simpler layout) without losing information or structure.
Guideline 2.4 Navigable
Create content that can be presented in different ways (for example simpler layout) without losing information or structure.
Guideline 4.1 Compatible
Maximize compatibility with current and future user agents, including assistive technologies.

Integrating accessibility traits into the components of your user interface ensures that users can interact with your content effectively, respecting all the guidelines. Both UIKit and SwiftUI components have accessibility traits properties. The accessibility trait defines the role of each component in providing information to users on how they could interact with it. For example, when VoiceOver highlights a button, it will read the button label first and then provide additional context by specifying it as a 'button,' leveraging the built-in .isButton trait.

There are a number of different traits you can adopt to better describe the functionality of your interface elements to VoiceOver, however, the accessibility traits vary slightly depending on the framework you are using.

You can find the complete list of these traits in the Apple documentation for accessibilityTraits in SwiftUI and UIAccessibleTraits in UIKit.

Here are some examples of traits you can use with your SwiftUI views:

  • .isHeader: identifies a textual header element that divides content like the navigationTitle
  • .isButton: recognizes components as buttons, enabling double-tap actions like Shazam's button.
  • .isSummaryElement: provides launch summary info like the weather conditions in the Weather app.
  • .startMediaSession: pauses VoiceOver during recording audio or generally during a media session.
  • .allowsDirectInteraction: enables users to interact bypassing the assistive technology layer, using only standard touch controls, like playing piano on GarageBand

How to use them

Traits are built-in the native components, and using modifiers, you can either add new traits or remove the default trait of the component to customize its behaviour. Alternatively, you can use the Accessibility section of the Identity Inspector in the Xcode's Inspectors panel once a component is selected.

In the following example when VoiceOver highlights the SF Symbol it says “button”, so the user will expect some instruction on the interaction method, like “double-tap to trigger an action”.

Image(systemName: "heart")
	.accessibilityRemoveTraits(.isImage)
	.accessibilityAddTraits(.isButton)

Removing and adding accessibility traits to a View in SwiftUI

@IBOutlet weak var imageTraitDemo: UIImageView!

imageTraitDemo.accessibilityTraits.remove(.image)
imageTraitDemo.accessibilityTraits.insert(.button)

Removing and adding accessibility traits to a View in UIKit

When to use them

If your application interface includes custom interface components or you have modified the role of an existing SwiftUI component, you must remove/add the correct traits to them to guarantee that your user interface is prepared to be read by assistive technologies.

An example could be a custom interface element that when you double tap on an image it triggers some action (like on the Instagram app, when you double tap on an image it triggers the like action).

Initially the Image view on SwiftUI has the .isImage trait associated with it, so your application will not communicate to the assistive technology that the user can interact with the image. You have to specify the correct traits to guide the user correctly.

Image(systemName: isSelected ? "heart.fill" : "heart")
	.foregroundStyle( isSelected ? .red : .white)
	.font(.system(size: 200))
	
	.onTapGesture(count:2) {
		isSelected.toggle()
	} 

	.accessibilityRemoveTraits(.isImage)
	.accessibilityAddTraits(.isButton)
	.accessibilityAddTraits(isSelected ? .isSelected : [])

	.accessibilityLabel(Text("Liked"))
	.accessibilityHint("Double tap to like it")

	.accessibilityAction {
		isSelected.toggle()
	}

Adding traits to the image component to expose to VoiceOver correctly what can be done with it

When not to use them

Traits are powerful in defining the function of each element in the user interface. SwiftUI interface components have traits associated with them by default, so if your application includes only native components you don't have to worry about adding traits to them.