Table of Contents
Customising Gestures for an Accessible Experience
Custom gestures can sometimes conflict with VoiceOver's own swipe commands, making your app challenging or impossible to use for some. This guide shows how to implement and customise gestures for an Accessible experience
🎯 Why It Matters
Many iOS apps use gestures to streamline interactions—think of swiping to delete an email or pinching to zoom in a photo gallery. However, users who rely on assistive technologies like VoiceOver interact with these gestures in a different way. Custom gestures can sometimes conflict with VoiceOver's own swipe commands, making your app challenging or impossible to use for some.
Real-World Context: Swipe to Delete or Archive
A common feature in email clients and messaging apps is the "swipe to delete" or "swipe to archive" action. While this gesture feels natural to many users, it can be problematic for people using screen readers if there is no accessible fallback. Without an alternative, VoiceOver users might not be able to activate this action at all, because VoiceOver already uses swipe gestures for navigation.
Key accessibility barriers this solution addresses:
- Gesture Conflicts: Custom gestures that interfere with VoiceOver's navigation commands (swipe right/left to move between elements)
- Discoverability: Gesture-only actions that aren't announced or discoverable by screen readers
- Alternative Access: Users with limited dexterity or motor impairments who cannot perform complex multi-touch gestures
đź’» Implementation
Incorrect Code Example: Custom Swipe That Conflicts with VoiceOver
Demo Description
This code simulates a list where swiping on an item archives it, but it doesn’t offer a workable method for assistive technology users.
// SwiftUI
// INACCESSIBLE: Custom swipe gesture isn't announced or discoverable by VoiceOver.
import SwiftUI
struct EmailListView: View {
@State private var emails = ["Meeting notes", "Shopping list", "Vacation plans"]
var body: some View {
List {
ForEach(emails, id: \.self) { email in
Text(email)
.gesture(
DragGesture(minimumDistance: 50)
.onEnded { value in
if value.translation.width < 0 {
emails.removeAll { $0 == email }
}
}
)
}
}
}
}Code Explanation
Here, a left swipe removes an email from the list. However, VoiceOver users rely on swipe gestures to navigate through the list itself, so this custom gesture may interfere with or never trigger under VoiceOver. There’s no button or menu option to achieve the same action, leaving some users stuck.
Correct Code Example: Offering an Accessible Alternative to Pinch-to-Zoom
Demo Description
Let’s look at another example which shows how to keep the familiar pinch-to-zoom interaction while adding “Zoom out” and “Zoom in” buttons that VoiceOver can discover, giving people with limited dexterity or screen-reader users a one-finger alternative.
// SwiftUI
import SwiftUI
struct PhotoGalleryView: View {
@State private var scale = 1.0
var imageName: String
var body: some View {
Image(imageName)
.resizable()
.scaledToFit()
.scaleEffect(scale)
.gesture(MagnificationGesture().onChanged { scale = $0 })
.overlay(
HStack {
Button({ scale -= 0.1 }) {
Image(systemName: "minus.magnifyingglass")
.accessibilityLabel("Zoom Out")
}
Button({ scale += 0.1 }) {
Image(systemName: "plus.magnifyingglass")
.accessibilityLabel("Zoom In")
}
}
)
}
}Code Explanation
Here, users can pinch to zoom by default. However, if they find the pinch gesture difficult—or if VoiceOver conflicts with multi-touch gestures—they can tap the “Zoom In” or “Zoom Out” buttons, which are labelled for accessibility.
âś… Best Practices
Do's
- ✓Offer an alternative method for every custom gesture (buttons, menus, or accessibility actions)
- ✓Preserve standard iOS gestures where possible—avoid reinventing them
- ✓Provide clear accessibility labels for all alternative controls
- ✓Use `.accessibilityAction()` for custom actions with user-friendly names
- ✓Test all gestures with VoiceOver enabled to verify they work or have accessible alternatives
- ✓Make alternative controls visible when possible, not just available to assistive technologies
- ✓Ensure multi-touch gestures have single-touch alternatives
Don'ts
- âś—Create gesture-only interactions without accessible alternatives
- âś—Override standard iOS gestures that conflict with VoiceOver navigation
- âś—Hide critical functionality behind complex multi-touch gestures
- âś—Assume all users can perform pinch, rotate, or multi-finger gestures
- âś—Forget to label icon-only buttons used as gesture alternatives
- âś—Make gestures the only way to discover or access features
- âś—Implement custom gestures that interfere with system-level accessibility features
🔍 Common Pitfalls
Gesture-Only Actions
Implementing swipe-to-delete, pinch-to-zoom, or other gestures without any alternative method for triggering the same action
Conflicting Gestures
Creating custom swipe gestures that interfere with VoiceOver's navigation (swipe right to go forward, swipe left to go back)
Undiscoverable Actions
Custom gestures that aren't announced by VoiceOver or documented anywhere in the interface
Missing Accessibility Actions
Failing to use `.accessibilityAction()` to expose gesture-based functionality to assistive technologies
Icon-Only Alternatives
Providing alternative buttons but forgetting to add accessibility labels to icon-based controls
Complex Gesture Requirements
Requiring precise or complex gestures (multi-finger swipes, long presses with drag) without simpler alternatives
VoiceOver/TalkBack
Screen readers use swipe gestures for their own navigation (swipe right to move forward, swipe left to move back, swipe up/down to adjust controls). Custom swipe gestures will conflict with these commands. When VoiceOver is enabled, provide button alternatives or use `.accessibilityAction()` to make custom actions available through the VoiceOver rotor. VoiceOver users can access custom actions by selecting an element and swiping up or down to choose from available actions
Switch Control
Users relying on switch control cannot perform multi-touch or complex gestures. All functionality must be accessible through single-tap alternatives or sequential single-switch inputs
Voice Control
Gesture-based interactions aren't accessible via voice commands. Alternative buttons with clear labels enable voice control users to say "Tap Archive" or "Tap Zoom In"
AssistiveTouch
Users with motor impairments who use AssistiveTouch may struggle with precise swipes or multi-touch gestures. Visible button alternatives make all functionality accessible
Full Keyboard Access
Gesture-based interactions are not accessible to keyboard users. Providing button alternatives ensures keyboard navigation works properly
đź§Ş Testing Steps
- 1Enable VoiceOver: Settings → Accessibility → VoiceOver
- 2Navigate to gesture-based controls: Swipe through your interface
- 3Test standard navigation: Verify VoiceOver swipe gestures work correctly
- 4Attempt custom gestures: Try to trigger custom gestures with VoiceOver enabled
- 5Locate alternative controls: Check that alternative buttons or actions are discoverable
- 6Test multi-touch gestures: Verify pinch-to-zoom and other multi-touch interactions
- 7Use alternative methods: Test zoom buttons, archive buttons, and other alternatives
- 8Enable Switch Control: Test that all functionality is accessible via single-switch input
- 9Test with Voice Control: Verify alternative controls can be activated by voice
Become a member to read this solution, and all of Ma11y.
This resource is part of our member knowledge base. Log in or create an account to unlock:
- Complete accessibility guidance and implementation examples
- Curated compliance frameworks and checklists
- Early access to new tools and features
