swiftuiaccessibility

How to conditionally apply an accessibility action?


SwiftUI has the handy .accessiblityAction() ViewModider that adds an accessibility action to a view that you are creating. Keyboard users and VO users can learn about the actions attached to the View and trigger them.

I want to be able to conditionally apply an action based on a boolean. Something like this:


Button {
    print("Button tapped")
} label: {
    Text("Button title")
}
if addActionToButton.wrappedValue {
    .accessibilityAction(named: "Button action") {
        print("Button action triggered")
    }
}

You can't put a ViewModifier like accessibilityAction inside an if statement however.

.accessibilityLabel has a variant that takes an isEnabled parameter. When the isEnabled condition is false, it does not apply the accessibility label:

@State addA11Label: Bool

Button {
    print("Button tapped")
} label: {
    Text("Button title")
}
.accessibilityLabel("Button foo. Double-tap to do stuff.", isEnabled: addA11Label.wrappedValue)

I want a accessibilityAction isEnabled parameter, but no such luck.

How could I conditionally add an accessibilityAction to my Button (or other view)?


Solution

  • You could create a custom view extension that uses @ViewBuilder to add the action only when a specified Boolean is true.

    Example:

    import SwiftUI
    
    extension View {
        @ViewBuilder
        func conditionalAccessibilityAction(
            _ condition: Bool,
            name: String,
            perform action: @escaping () -> Void
        ) -> some View {
            if condition {
                self.accessibilityAction(named: name, perform: action)
            } else {
                self
            }
        }
    }
    
    struct ContentView: View {
        @State private var addActionToButton: Bool = true
    
        var body: some View {
            VStack {
                Button {
                    print("Button tapped")
                } label: {
                    Text("Button Title")
                }
                .conditionalAccessibilityAction(
                    addActionToButton,
                    name: "Button action"
                ) {
                    print("Button action triggered")
                }
                
                Toggle("Add Accessibility Action", isOn: $addActionToButton)
                    .padding()
            }
            .padding()
        }
    }
    
    struct ContentView_Previews: PreviewProvider {
        static var previews: some View {
            ContentView()
        }
    }
    

    The extension would check the boolean and apply .accessibilityAction(named:perform:) if the condition is met, otherwise it leaves the view unchanged.