Rob Whitaker
Oct 2 · 3 min read

Assistive technology, such as VoiceOver, works in natural reading direction. In English, and most other languages, this means top left through to the bottom right. Mostly this is the right decision for assistive technology to make. This is the order anyone not using assistive technology would experience your app. Sometimes though, we make designs that don’t read in this way.

By using the .accessibility(sortPriority: ) modifier we can set the order in which assistive technology accesses elements. To achieve this, you must group elements in a stack (HStack, VStack or ZStack). Then use the .accessibilityElement(children: .contain) modifier. The higher the number we give to .accessibility(sortPriority: ), the earlier VoiceOver will focus on the item. This means an element with a priority of 2 comes before priority 1, and so on.

VStack {   Text(“Read this last”)
.accessibility(sortPriority: 0)
Text(“Read this first”)
.accessibility(sortPriority: 2)
Text(“Read this second”)
.accessibility(sortPriority: 1)
}
.accessibilityElement(children: .contain)
Text highlighted by VoiceOver
Text highlighted by VoiceOver

One example of using this might be captioning a large image. In SwiftUI images are accessible by default. This doesn’t mean we should focus on the image as the first element — the title is usually more meaningful. Here, we’d set the sort priority of the image to 0 so it receives focus after VoiceOver has read the title and caption.

VStack {   Image(“shuttle”)
.accessibility(sortPriority: 0)
Text(“Shuttle”)
.font(.largeTitle)
.accessibility(sortPriority: 2)
Text(“This is an image of a shuttle on the launch pad”)
.accessibility(sortPriority: 1)
}
.accessibilityElement(children: .contain)

Another use of this could be a custom stepper control. We’d want VoiceOver to focus on the value first to orientate your user and inform them which value they’re starting with. Then VoiceOver should follow with the decrease and increase buttons. We’d achieve this like this:

HStack {   Button(action: {
self.value -= 1
}) {
Text(“Decrease”)
}
.accessibility(sortPriority: 1)
Text(String(value))
.accessibility(sortPriority: 2)
Button(action: {
self.value += 1
}) {
Text(“Increase”)
}
}
.accessibilityElement(children: .contain)
A custom stepper control
A custom stepper control

.Contain

As of October 2019, the sort priority only works for elements inside a stack where the stack has the modifier of .accessibilityElement(children: .contain). I don’t believe this is intentional, hopefully, future releases of SwiftUI will drop this requirement.


Thanks for reading. This story is part of a series on SwiftUI Accessibility. Check out my other guides in this series:
SwiftUI Accessibility: Dynamic Type
SwiftUI Accessibility: Named Controls
SwiftUI Accessibility: Images
SwiftUI Accessibility: Accessible User Interface

Flawless iOS

🍏 Community around iOS development, mobile design, and marketing

Rob Whitaker

Written by

iOS Engineer at Capital One.

Flawless iOS

🍏 Community around iOS development, mobile design, and marketing

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade