Inaccessible Action

Link to Inaccessible Action copied to clipboard
note

This is an experimental rule, and therefore its result(s) are considered to be in beta testing. Learn more about experimental rules and how you can help improve them.

WCAG 2.0 - 2.1.1 A Impact - Critical

An element that is an active control or contains an active control must have an action that can be activated using Assistive Technology.

Impact

Assistive Technology users should be able to activate an active control's action using assistive technology.

Confirmation

  1. Turn on VoiceOver
  2. Focus on the element
  3. One of the following will happen:
    • Inaccessible: The user will not be able to activate the active control's action using assistive technology.
    • Accessible: The user will be able to use an assistive technology to activate the active control.

How to Fix

An issue is found by this rule when:

  • a control and its label are within a parent view marked as isAccessibilityElement = true
  • the parent view does not have a separate gesture recognizer

and/or:

  • the control is not in the middle of the parent view, therefore cannot be activated with VoiceOver

UIKit

In storyboard:

  1. Select the element with an InaccessibleAction issue
  2. Ensure that the Inspectors Panel is visible
  3. Select the Identity Inspector
  4. Under Accessibility, there is a property called "Accessibility" with a checkbox called "Enabled" next to it. Ensure that the "Enabled" check box is selected for the active control

An alternative option is to change the element's accessibility path:

  1. Repeat steps 1-3 for the active control, its label and the view that contains the active control
  2. Under Accessibility, there is a property called "Accessibility" with a checkbox called "Enabled" next to it. Ensure that the "Enabled" check box is selected for the active control, but not for the label or its containing view
  3. In the code, change the accessibility path to include the containing view's active control and label as shown in the second step of the fourth item in the 'In code' section

Another solution is to have the active control use it's parent's accessibility activation point:

  1. Select the element with an InaccessibleAction issue
  2. Ensure that the Inspectors Panel is visible
  3. Select the active control in the element
  4. Select the Size Inspector
  5. Ensure that the active control is centered horizontally and vertically within its containing view

In code:

Find where the active control's isAccessibilityElement property was set and ensure that it is set to true.

buttonContainerView.isAccessibilityElement = true

Another option is to add a gesture recognizer to the active control's containing view. Find the view that contains the control and add a tap gesture recognizer.

buttonContainerView.addGestureRecognizer(UITapGestureRecognizer(target: self, selector: #selector(buttonTapped)))

Alternatively, you can change the active control to be in the center of the parent view, so the containing view's accessibilityActivationPoint activates the active control. Find the view that contains the control and ensure that the control is in the exact center of the parent view that contains it.

buttonContainerView.button.centerXAnchor.constraint(equalTo: buttonContainerView.centerXAnchor).isActive = true
buttonContainerView.button.centerYAnchor.constraint(equalTo: buttonContainerView.centerYAnchor).isActive = true

Additionally, you can fix this issue by changing the accessibility path to include the containing view's active control and label.

  1. Make the control's label and the parent view isAccessibilityElement = false
toggleContainerView.toggle.isAccessibilityElement = true
toggleContainerView.label.isAccessibilityElement = false
toggleContainerView.isAccessibilityElement = false
  1. Update the control's accessibility path to encapsulate both the label and the control
    // Assuming we are in a ViewController
let button = UIButton()

// If not within a ViewController, self.view should be replaced with the rootView of the screen
let rootview = self.view
let onScreenFrame = button.superview!.convert(button.frame, to: rootview)
button.accessibilityPath = UIBezierPath(rect: onScreenFrame)

SwiftUI

This accessibility issue cannot occur on most default elements and active controls in SwiftUI; however, it can occur with some custom active controls such as a custom slider, stepper or toggle. Consider using the .accessibilityRepresentation view modifier to make custom controls have the same accessibility representation as the corresponding default version of the control.

// Assuming we are in a completely custom Toggle view that is not made using SwiftUI's default Toggle element

    .accessibilityRepresentation {
        Toggle(isOn: $isOn) {
            Text("Puppy Mode")
            }
        }