How it works
AccessibilitySystemRotor identifies one of the rotors that VoiceOver already knows how to present—headings, links, landmarks, and similar categories that assistive-technology users navigate by swiping through the rotor control. Rather than naming a custom rotor yourself, you pass one of these built-in values to accessibilityRotor(_:entries:) so your own content becomes the destinations VoiceOver offers under a familiar, standard category. Reach for it when your view contains semantically meaningful elements—like section headings—that should plug into a system rotor VoiceOver users expect to find.
Pick a built-in rotor with a type property like .headings
AccessibilitySystemRotorexposes the system categories as static members, so you select one with leading-dot syntax instead of constructing it. The example chooses.headings, the rotor VoiceOver users open to jump between section titles; other members cover links, landmarks, and more.Attach it with the accessibilityRotor(_:entries:) modifier
You connect the rotor to your view hierarchy by passing the
AccessibilitySystemRotorvalue to.accessibilityRotor. Here.accessibilityRotor(.headings)is applied to theVStack, declaring that this container supplies the destinations for the system headings rotor.Supply destinations with AccessibilityRotorEntry
The modifier's trailing closure lists the navigable targets as
AccessibilityRotorEntryvalues, each carrying a label and an identifier. The example maps overheadingsto emitAccessibilityRotorEntry(heading, id: heading), so each title becomes a stop the rotor can move VoiceOver focus to.Make the content discoverable to the rotor
Entries should correspond to elements that are meaningful to assistive technology. The example marks each
Text(heading)with.accessibilityAddTraits(.isHeader), reinforcing that these are headings so the.headingssystem rotor and the elements it points at stay consistent.
.accessibilityRotor(.headings) to .accessibilityRotor(.links) and turn on VoiceOver—the same entries now appear under the Links rotor instead of Headings, showing how the AccessibilitySystemRotor value alone decides which standard category your content joins.Example & preview
Press Run live & edit to compile it in your browser — then edit the Swift on the left and the preview re-renders live.
struct AccessibilitySystemRotorDemo: View {
let headings = ["Introduction", "Methods", "Results"]
var body: some View {
VStack(alignment: .leading, spacing: 12) {
ForEach(headings, id: \.self) { heading in
Text(heading)
.font(.headline)
.accessibilityAddTraits(.isHeader)
}
}
.accessibilityRotor(.headings) {
ForEach(headings, id: \.self) { heading in
AccessibilityRotorEntry(heading, id: heading)
}
}
.padding()
}
}