Dunfey · Hotel WWDC as data, est. 1983
Front desk everything
Years
Topics

2026 SwiftUI & UI FrameworksAccessibility & Inclusion

WWDC26 · 20 min · SwiftUI & UI Frameworks / Accessibility & Inclusion

Enhance the accessibility of your reading app

Learn how to create robust reading experiences for VoiceOver, Speak Screen, and more. Find out how to provide intuitive text selection, clear navigation between lines and paragraphs, and continuous reading across individual elements and multiple pages.

Watch at developer.apple.com ↗

Transcript all transcripts

Chapters

Code shown on screen · 5 snippets

Link text elements together with navigation APIs swift · at 7:29 ↗
// Link text elements together with navigation APIs

import UIKit

class TravelGuidePageController: UIViewController {

    var paragraphs: [TravelGuideParagraph]

    func configureNavigationElements() {
        for (index, paragraph) in paragraphs.enumerated() {
            if index + 1 < paragraphs.count {
                paragraph.accessibilityNextTextNavigationElement = paragraphs[index + 1]
            }
            if index - 1 >= 0 {
                paragraph.accessibilityPreviousTextNavigationElement = paragraphs[index - 1]
            }
        }
    }
}
Link text elements together with a linked group swift · at 7:59 ↗
// Link text elements together with a linked group

import SwiftUI

struct PageView : View {
    @Namespace private var pageNamespace
    var paragraphs: [String
    var pageNumber: Int

    var body: some View {
        Text(paragraphs[0])
            .textSelection(.enabled)
            .accessibilityLinkedGroup(id: pageNumber, in: pageNamespace)

        Text(paragraphs[1])
            .textSelection(.enabled)
            .accessibilityLinkedGroup(id: pageNumber, in: pageNamespace)
    }
}
Turn pages automatically after reading swift · at 9:50 ↗
// Turn pages automatically after reading

import UIKit

class TravelGuidePageController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        self.lastParagraphView.accessibilityTraits.insert(.causesPageTurn)
    }

    override func accessibilityScroll(_ direction: UIAccessibilityScrollDirection) -> Bool {
        moveToPage(direction)
        var scrollString = "Page \(currentPage) of \(pages.count)"
        UIAccessibility.post(notification: .pageScrolled, argument: scrollString)
        return true
    }
}
Add actions to the editor rotor swift · at 11:45 ↗
// Add actions to the editor rotor

import UIKit

class TravelGuideParagraph: UITextView {

    override var accessibilityCustomActions: [UIAccessibilityCustomAction]? {
        get {
            let saveAction = UIAccessibilityCustomAction(name: "Save Recommendation") { _ in
                self.saveRecommendation()
            }
            saveAction.category = UIAccessibilityCustomAction.editCategory
            return (super.accessibilityCustomActions ?? []) + [saveAction]
        }
        set { }
    }

    private func saveRecommendation() -> Bool {
        ...
        return true
    }
}
Adopt UITextInput swift · at 16:10 ↗
// Adopt UITextInput

import UIKit

class ScannedPage: UIView, UITextInput {

    override init(frame: CGRect) {
        super.init(frame: frame)
        let interaction = UITextInteraction(for: .nonEditable)
        interaction.textInput = self
        addInteraction(interaction)
    }
   
    func selectionRects(for range: UITextRange) -> [UITextSelectionRect] {
        var rects: [UITextSelectionRect] = []

        let startLine = lineIndex(for: range.start)
        let endLine = lineIndex(for: range.end)

        for line in startLine...endLine {
            let rect = selectionRectFromImage(for: range, in: line)
            rects.append(rect)
        }

        return rects
    }
  
    func text(in range: UITextRange) -> String? {
        let nsRange = nsRange(from: range)
        guard let range = Range(nsRange, in: scannedText) else {
            return nil
        }
        return String(scannedText[range])
    }

    var tokenizer: any UITextInputTokenizer { CustomHandwritingTokenizer(textInput: self) }

    weak var inputDelegate: UITextInputDelegate?
  
      var selectedTextRange: UITextRange? {
        // Update visuals when assistive technologies change selection
        willSet { inputDelegate?.selectionWillChange(self) }
        didSet { inputDelegate?.selectionDidChange(self) }
    }
  
}

Resources