Preparing your App for VoiceOver: Accessibility Actions

Preparing your App for VoiceOver: Accessibility Actions

Ensure the interactions with the interface elements of your app are possible with assistive technologies

Some features and interactions of our app's interface might not be accessible through assistive APIs, maybe because you created new accessible elements to group semantic views or, simply, might not be easy to interact with it. However, we can still perform some operations by leveraging the UIAccessibilityAction informal protocol. This protocol allows accessibility elements to perform specific actions.

According to the official Apple Documentation, accessibility actions are:

A set of methods that accessibility elements can use to support specific actions.
Apple Documentation

Accessibility Actions are fundamental for assistive technologies:

  1. VoiceOver is informed that actions are available and the user can activate them by double tapping. If more actions are available VoiceOver will announce ‘Actions available’ and allow users to swipe vertically to hear the available options and interact with the view.
0:00
/0:19

Custom Accessibility Actions in the Mail app using VoiceOver

  1. Switch Control users are presented a menu of all the available actions.
Custom Accessibility Actions in the Mail app using Switch Control


Before exploring how to use accessibility actions it's important to know that there are different kinds of actions available to the user via assistive technologies. In this article, we will focus just on some of them.

How to use them

Both in UIKit and SwiftUI, you have the flexibility to define custom actions for our accessibility elements.

SwiftUI

In SwiftUI, you can take advantage of a few modifiers that will help you customize the accessible user experience regarding interactions.
If the interaction is not that complex you can use the .accessibilityAction(_:_:) modifier directly on the View.


// Perform a simple action when the accessibility action is triggered

import SwiftUI

var body: some View {
    AccessibleView()
        .accessibilityAction {
            print("Action Performed")
        }
}

You can even use the.accessibilityAction(named:_:) to give a name to the action. Switch control will display the name in the menu while VoiceOver will announce that actions are available so the user can swipe up or down to know the name.

If you need to define a set of actions that can be performed you can use the .accessibilityActions(_:) modifier. This will add multiple accessibility actions to the view.


// Creating a SwiftUI view defining multiple accessibility actions

import SwiftUI

var body: some View {
    AccessibleView()
        .accessibilityActions {
            Button {
                // Perform first action here
            } label: {
                Text("First Action")
            }
            Button {
                // Perform second action here
            } label: {
                Text("Second Action")
            }
        }
}

As written in the Apple documentation this modifier can also attach a dynamic number of actions to a view. The user will access each one of these actions through vertical swipes or contextual menu depending on the accessibility API.

Using the .accessibilityAction(_: _:) or the .accessibilityActions(_:) modifiers will give the .isButton accessibility trait to the view.

Another scenario may be views in which the user can increase values inside the view. You can easily increase a value in the view with swipe-up or swipe-down gestures by using an Adjustable Action with the .accessibilityAdjustableAction(_:) modifier.


// Creating a SwiftUI view with a control that can be adjusted with the .accessibilityAdjustableAction modifier

import SwiftUI

struct ContentView: View {
    @State var value: Double = 0.0
    
    var body: some View {
        AccessibleView(value: $value, in: 0.0...100.0)
            .accessibilityAdjustableAction { direction in
                switch direction {
                case .increment:
                    value += 1.0
                case .decrement:
                    value -= 1.0
                @unknown default:
                    break
                }
            }
    }
}

UIKit

Similar to SwiftUI, in UIKit, we can define a set of actions linked to the single accessible element, using an array of custom actions to display along with the built-in actions. The array will contain one or more UIAccessibilityCustomAction objects defining the supported actions.


// Defining and adding accessibility actions to a view in UIKit


import UIKit

class AccessibleViewController: UIViewController {
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Set up the accessibility custom actions after loading the view.
        setupAccessibilityActions()
    }

    
    func setupAccessibilityActions() {
        let actionOne = UIAccessibilityCustomAction(name: "First Action", actionHandler: { _ in
            // Implement the action for "First Action"
            print("First Action performed")
            return true
        })

        let actionTwo = UIAccessibilityCustomAction(name: "Second Action", actionHandler: { _ in
            // Implement the action for "Second Action"
            print("Second Action performed")
            return true
        })

        accessibilityCustomActions = [actionOne, actionTwo]
    }

}

By creating a custom subclass of the component, we can override certain methods within the UIAccessibilityAction protocol. For instance, if we intend to associate a simple action with a label, subclassing the UILabel class and overriding the accessibilityActivate() method allows you to achieve this.


// Creating a UILabel subclass with overridden accessibilityActivate method

import UIKit

class ActionLabel : UILabel {
    override func accessibilityActivate() -> Bool {
        print("Accessibility action performed")
        return true
    }
}

In case you are using a slider or some other component with a value that needs to be adjusted you can override the accessibilityIncrement() and accessibilityDecrement() method inside your class.


// Creating a UISlider subclass implementing custom accessibility behavior

import UIKit

class CustomAccessibleSlider: UISlider {

    override func accessibilityIncrement() {
        super.accessibilityIncrement()
        print("increment performed")
    }

    override func accessibilityDecrement() {
        super.accessibilityDecrement()
        print("decrement performed")
    }
}

You must provide an implementation of these two methods for every Accessibility Element that has the adjustable trait.

You can check the accessibility actions available also with the Accessibility Inspector.

Actions Section of the Accessibility Inspector

To know more about the Accessibility Inspector, check out the article:

Testing your app’s accessibility with the Accessibility Inspector
Enhance your app accessibility by testing and auditing it with the Accessibility Inspector to better support assistive technologies and discover possible accessibility issues.

When to use them

The interaction is not performable through Assistive Technologies

Custom actions become necessary when certain functionalities within an application aren't accessible through assistive technologies. An example may be the Mail app, the Phone app or any app containing a list.

When VoiceOver is enabled, the interaction to access swipe actions on a list row changes. Instead of swiping horizontally, which is used in VoiceOver to navigate the interface, the user can swipe vertically to access the same actions. This ensures that users relying on assistive technologies can seamlessly navigate and interact with the app's features. Another similar example is actions that are available with long presses.

Simplify complex interactions

Some functionalities within an application might be accessible but not easily actionable through assistive technologies. For example for Switch Control users, some actions like drag-and-drop or long press can be challenging. To make it easier, the functionalities associated with these interactions can be provided directly on the view through accessibility actions. An example of a simplified action could be a rating view like the one present in the App Store app.

0:00
/0:20

Custom Actions in the App Store app using VoiceOver

When not to use them

Too many custom actions

Introducing too many custom actions alongside existing native accessibility features can overwhelm users' cognitive load. It might lead to confusion or difficulty in selecting the appropriate action affecting also the overall usability of the app with assistive technologies.

Compliance with Web Content Accessibility Guidelines

In the WCAG 2.2 (Web Content Accessibility Guidelines), the industry-standard accessibility reference, we can see the following guidelines:

Operable
"User interface components and navigation must be operable."
Guideline 1.3 Adaptable
"Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text."
Guideline 4.1 Compatible
"Maximize compatibility with current and future user agents, including assistive technologies."

You can have more information about the WCAG in the following article:

Exploring accessibility regulations and guidelines
Explore the world of accessibility laws, regulations, guidelines, legal aspects, and the profound impact they have on shaping a more inclusive technological future.

Related Articles