Skip to content
Development
Skill

/ios-accessibility

Build and audit SwiftUI, UIKit, and AppKit accessibility for VoiceOver, Voice Control, Switch Control, Full Keyboard Access, Dynamic Type, focus restoration, labels/traits/actions, traversal, custom rotors, NSAccessibility, XCTest checks, adaptive system preferences, and App

From plugin
swift-ios-skills
98186 skills1 MCP
Install
$ npx -y skills add dpearson2699/swift-ios-skills --skill ios-accessibility --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/ios-accessibility

Context preview

The summary Claude sees to decide when to auto-load this skill.

Build and audit SwiftUI, UIKit, and AppKit accessibility for VoiceOver, Voice Control, Switch Control, Full Keyboard Access, Dynamic Type, focus restoration, labels/traits/actions, traversal, custom rotors, NSAccessibility, XCTest checks, adaptive system preferences, and App

SKILL.md

ios-accessibility.SKILL.md
name: ios-accessibility
description: "Build and audit SwiftUI, UIKit, and AppKit accessibility for VoiceOver, Voice Control, Switch Control, Full Keyboard Access, Dynamic Type, focus restoration, labels/traits/actions, traversal, custom rotors, NSAccessibility, XCTest checks, adaptive system preferences, and App Store accessibility declarations. Use when implementing accessible UI, fixing an accessibility audit, testing assistive-technology behavior, or substantiating App Store Accessibility Nutrition Labels."

iOS/macOS Accessibility - SwiftUI, UIKit, and AppKit

Build SwiftUI, UIKit, and AppKit interfaces that remain operable with VoiceOver, Switch Control, Voice Control, Full Keyboard Access, and adaptive accessibility settings.

Contents

  • [Core Principles](#core-principles)
  • [How VoiceOver Reads Elements](#how-voiceover-reads-elements)
  • [SwiftUI Accessibility Modifiers](#swiftui-accessibility-modifiers)
  • [Focus Management](#focus-management)
  • [Dynamic Type](#dynamic-type)
  • [Custom Rotors](#custom-rotors)
  • [System Accessibility Preferences](#system-accessibility-preferences)
  • [Decorative Content](#decorative-content)
  • [Voice Control](#voice-control)
  • [Switch Control](#switch-control)
  • [Full Keyboard Access](#full-keyboard-access)
  • [Assistive Access (iOS 18+)](#assistive-access-ios-18)
  • [UIKit Accessibility Patterns](#uikit-accessibility-patterns)
  • [AppKit Accessibility Patterns](#appkit-accessibility-patterns)
  • [Accessibility Custom Content](#accessibility-custom-content)
  • [App Store Accessibility Nutrition Labels](#app-store-accessibility-nutrition-labels)
  • [Testing Accessibility](#testing-accessibility)
  • [Common Mistakes](#common-mistakes)
  • [Review Checklist](#review-checklist)
  • [References](#references)

---

Core Principles

1. Prefer semantic system controls; custom controls must expose the same name, role, value, state, and actions. 2. Preserve every task across assistive input: do not make a gesture, color, motion, hover state, or visual arrangement the only path to meaning or action. 3. Keep focus and traversal intentional across navigation, presentation, updates, and dismissal. 4. Let text, layout, contrast, transparency, and motion adapt to the user's accessibility settings. 5. Treat App Store accessibility declarations as evidence-backed product claims, not as a summary of isolated control-level support.

How VoiceOver Reads Elements

VoiceOver reads element properties in a fixed, non-configurable order:

**Label -> Value -> Trait -> Hint**

Design your labels, values, and hints with this reading order in mind.

SwiftUI Accessibility Modifiers

See [references/a11y-patterns.md](references/a11y-patterns.md) for detailed SwiftUI modifier examples (labels, hints, traits, grouping, custom controls, adjustable actions, and custom actions).

Focus Management

Focus management is where most apps fail. When a sheet, alert, or popover is dismissed, VoiceOver focus MUST return to the element that triggered it.

This section is about accessibility focus for assistive technologies. For keyboard focus, directional focus, `focusSection()`, scene-focused values, and `UIFocusGuide`, use the `focus-engine` skill.

Audit element order and grouping in [Traversal Order](#traversal-order); route keyboard-focus mechanics to `focus-engine`.

`@AccessibilityFocusState` (iOS 15+)

`@AccessibilityFocusState` is a property wrapper that reads and writes the current accessibility focus. It works with `Bool` for single-target focus or an optional `Hashable` enum for multi-target focus.

struct ContentView: View {
    @State private var showSheet = false
    @AccessibilityFocusState private var focusOnTrigger: Bool

    var body: some View {
        Button("Open Settings") { showSheet = true }
            .accessibilityFocused($focusOnTrigger)
            .sheet(isPresented: $showSheet) {
                SettingsSheet()
                    .onDisappear {
                        // Slight delay allows the transition to complete before moving focus
                        Task { @MainActor in
                            try? await Task.sleep(for: .milliseconds(100))
                            focusOnTrigger = true
                        }
                    }
            }
    }
}

Multi-Target Focus with Enum

enum A11yFocus: Hashable {
    case nameField
    case emailField
    case submitButton
}

struct FormView: View {
    @AccessibilityFocusState private var focus: A11yFocus?

    var body: some View {
        Form {
            TextField("Name", text: $name)
                .accessibilityFocused($focus, equals: .nameField)
            TextField("Email", text: $email)
                .accessibilityFocused($focus, equals: .emailField)
            Button("Submit") { validate() }
                .accessibilityFocused($focus, equals: .submitButton)
        }
    }

    func validate() {
        if name.isEmpty {
            focus = .nameField // Move VoiceOver to the invalid field
        }
    }
}

Custom Modals

Custom overlay views need the `.isModal` trait to trap VoiceOver focus and an escape action for dismissal:

CustomDialog()
    .accessibilityAddTraits(.isModal)
    .accessibilityAction(.escape) { dismiss() }

Test dismissal as part of the modal contract: users must be able to dismiss the overlay with the relevant assistive-technology escape gesture or keyboard escape path, and focus should return to the trigger or next logical target.

Accessibility Notifications (UIKit)

When you need to announce changes or move focus imperatively in UIKit contexts:

// Announce a status change (e.g., "Item deleted", "Upload complete")
UIAccessibility.post(notification: .announcement, argument: "Upload complete")

// Partial screen update -- move focus to a specific element
UIAccessibility.post(notification: .layoutChanged, argument: targetView)

// Full screen transition -- move foc
Read more
Ships withswift-ios-skills

86 agent skills optimized for iOS 26+ development with Swift 6.3 and modern Apple frameworks.

Get the whole plugin
Stats
981
Stars
50
Forks
Active
Maintenance
Python
Language
9d ago
Last commit
5mo ago
Created

Repo: dpearson2699/swift-ios-skills

Other skills on swift-ios-skills.