TechnologiesSwiftUI

AccessibilityRotorContentBuilder struct

iOSmacOStvOSwatchOSvisionOSiOS 15.0+✓ renders

Result builder you use to generate rotor entry content.

How it works

AccessibilityRotorContentBuilder is the result builder that assembles the contents of a custom accessibility rotor. When you call accessibilityRotor(_:), the trailing closure is annotated with this builder, so the expressions you write inside it are collected into the ordered set of entries that VoiceOver presents when a user selects the rotor. Reach for it whenever you want to give assistive-technology users a fast, navigable index into a screen's important content rather than forcing them to swipe through every element in sequence.

  1. Open a rotor closure with accessibilityRotor(_:)

    Attaching accessibilityRotor("Folders") to a view declares a named rotor and hands you a content closure. That closure is where AccessibilityRotorContentBuilder does its work: it transforms the views you list into the rotor's navigation entries. Here the rotor is applied to the ScrollView, scoping the rotor to that scrollable region.

  2. Produce entries inside the builder

    Inside the builder closure you describe entries rather than visible UI. Each AccessibilityRotorEntry(name, id: name, in: "folders") becomes one stop in the rotor, and the builder gathers them into the final ordered list. The first argument supplies the label VoiceOver speaks, while id and the namespace "folders" tell SwiftUI which on-screen element the entry points to.

  3. Generate entries dynamically with ForEach

    Because AccessibilityRotorContentBuilder understands ForEach, you can build entries from a collection instead of writing them by hand. Iterating ForEach(messages, id: \.self) emits one entry per element of messages, so the rotor's contents stay in sync with the data driving the view.

  4. Anchor each entry to a real view

    An entry is only useful if it can move focus to something on screen. The matching .accessibilityRotorEntry(id: name, in: "folders") modifier on each Text registers that view in the "folders" namespace, and the entry's shared id and namespace let the rotor jump VoiceOver focus directly to it.

Try it — Filter the builder's ForEach(messages, id: \.self) down to a subset, such as iterating messages.filter { $0.hasPrefix("S") }, and observe that the rotor now lists only Sent, even though every folder still appears in the scroll view.

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.

AccessibilityRotorContentBuilder.swift
struct AccessibilityRotorContentBuilderDemo: View {
    let messages = ["Inbox", "Drafts", "Sent", "Archive"]
    var body: some View {
        ScrollView {
            VStack(alignment: .leading, spacing: 12) {
                ForEach(messages, id: \.self) { name in
                    Text(name)
                        .font(.headline)
                        .accessibilityRotorEntry(id: name, in: "folders")
                }
            }
            .padding()
        }
        .accessibilityRotor("Folders") {
            ForEach(messages, id: \.self) { name in
                AccessibilityRotorEntry(name, id: name, in: "folders")
            }
        }
    }
}
Live preview
Inbox Drafts Sent Archive
Inbox Drafts Sent Archive
swift → lexer → parser → sema → uiir → canvas Open in Studio ↗
What's new in SwiftUI 27 →