重要前提
安装AI Skills的关键前提是:必须科学上网,且开启TUN模式,这一点至关重要,直接决定安装能否顺利完成,在此郑重提醒三遍:科学上网,科学上网,科学上网。查看完整安装教程 →
swift-accessibility-skill by pasqualevittoriosi/swift-accessibility-skill
npx skills add https://github.com/pasqualevittoriosi/swift-accessibility-skill --skill swift-accessibility-skill为所有支持的平台上的 SwiftUI、UIKit 和 AppKit 应用无障碍功能。涵盖 App Store 无障碍营养标签的所有 9 个类别——VoiceOver、语音控制、更大字体、深色界面、不依赖颜色区分、足够对比度、减弱动态效果、字幕和音频描述。
此技能优先使用原生平台 API(提供免费的自动支持)和基于事实的指导,不涉及架构观点。
在初稿中就包含无障碍功能——永远不要先写一个裸元素,之后再打补丁。后期改造无障碍功能更困难,容易被跳过,并且效果不如从一开始就构建进去。
除非模式不明显,否则不添加内联注释。用 // [VERIFY] 标记推断出的标签,因为 SF Symbol 名称并不总是与预期的面向用户的含义匹配。
| 情况 | 首次编写时需要 |
|---|---|
Button / NavigationLink — 仅图标 | 使用 .accessibilityLabel("…") 并加上 // [VERIFY] |
Button / — 有可见文本 |
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
NavigationLink| 无需额外操作——文本会自动成为标签 |
Image — 有含义 | .accessibilityLabel("…") |
Image — 装饰性 | .accessibilityHidden(true) |
withAnimation / .transition / .animation | @Environment(\.accessibilityReduceMotion) + 控制动画 |
.font(.system(size:)) | 替换为 .font(.body) 或 @ScaledMetric |
| 颜色传达状态/状态 | 在颜色旁边添加形状、图标或文本 |
非 Button 上的 onTapGesture | .accessibilityElement(children: .ignore) + .accessibilityAddTraits(.isButton) + .accessibilityLabel |
| 自定义滑块 / 开关 / 步进器 | .accessibilityRepresentation { … } 或 .accessibilityValue + .accessibilityAdjustableAction |
| 异步内容变更 | 使用可用性防护发布通知(iOS 17+ 使用 AccessibilityNotification.Announcement,回退到 UIAccessibility.post) |
系统 .sheet / .fullScreenCover | 无需额外操作——SwiftUI 会自动捕获焦点(自定义覆盖层仍需要焦点管理) |
AVPlayer / 视频 | 使用 AVPlayerViewController——免费获得字幕和音频描述 |
| 自定义可点击视图 | .frame(minWidth: 44, minHeight: 44) |
| 任何新的 SwiftUI 视图 | 使用 Xcode 画布变体验证(见无障碍摘要) |
NSButton — 仅图标 (AppKit) | 使用 setAccessibilityLabel("…") 并加上 // [VERIFY] |
自定义 NSView 交互元素 (AppKit) | setAccessibilityElement(true) + 角色 (setAccessibilityRole(.button)) + 标签 |
| AppKit 模态/弹出 UI | 捕获焦点并确保关闭操作可通过键盘和 VoiceOver 访问 |
| 任何新的 AppKit 视图/控制器 | 使用无障碍检查器和完整键盘导航验证 |
优先使用原生控件(Button、Toggle、Stepper、Slider、Picker、TextField)——它们会自动获得完整的无障碍支持。自定义交互视图需要显式工作。对于 AppKit,优先使用原生控件(NSButton、NSPopUpButton、NSSlider、NSSegmentedControl、NSTextField),然后再考虑自定义 NSView 交互。
示例 — 仅图标按钮:
Button {
shareAction()
} label: {
Image(systemName: "square.and.arrow.up")
}
.accessibilityLabel("Share") // [VERIFY] 确认标签与意图匹配
示例 — 根据减弱动态效果控制动画:
@Environment(\.accessibilityReduceMotion) private var reduceMotion
withAnimation(reduceMotion ? nil : .spring()) {
isExpanded.toggle()
}
完整的测试和验证流程 → references/testing-auditing.md
在回答之前,选择一个最符合用户意图的主要参考文件并首先加载。仅当请求明确跨越多个领域(例如,VoiceOver + 动态类型 + WCAG 映射)或主要文件未涵盖所需标准时,才加载额外的参考文件。
应用初稿规则——在初稿中包含无障碍功能,无需注释。对于 iOS 15 之后引入的 API,始终添加 #available 防护并提供旧版系统的回退行为。编写后,根据初稿规则表进行验证——在输出前修复任何遗漏。在代码之后,附加无障碍摘要(见下文)。
静默应用修复,无需注释。对于 iOS 15 之后引入的 API,始终添加 #available 防护并提供旧版系统的回退行为。修复后,根据初稿规则表进行验证——在输出前修复任何遗漏。在代码之后,附加无障碍摘要。
examples/before-after-swiftui.md、examples/before-after-uikit.md 或 examples/before-after-appkit.mdreferences/platform-specifics.md仅当用户明确要求时("audit"、"how accessible is this?"、"review accessibility")。
快速修复模式——当用户要求仅限阻塞/关键问题的范围时(例如:"just fix the blockers"、"quick fix"、"critical only"):仅处理阻碍辅助技术和降低体验的问题。跳过支持不完整。
全面模式(默认)——处理所有严重级别的问题,包括支持不完整和营养标签缺口。
references/wcag-mapping.mdresources/qa-checklist.md→ references/nutrition-labels.md —— 包含官方通过/失败标准的全部 9 个类别
当用户要求准备或起草 App Store 无障碍营养标签建议时,输出此格式:
**无障碍营养标签建议**
**评估的应用版本:** [版本号或 "当前构建"]
**审查的范围:** [评估的常见任务 / 屏幕]
**您可以声明:**
- [每个常见任务都是 ✅ 或 — 的标签]
**您可以声明它们的原因:**
- [标签]:[与已完成的常见任务覆盖范围相关的简要原因]
**您不应声明:**
- [被任何 ❌ 阻碍的标签]
- [不适用的标签]
**您不应声明它们的原因:**
- [标签]:[被阻碍的任务或该标签不适用的原因]
**常见任务验证**
| 常见任务 | VoiceOver | 语音控制 | 更大字体 | 深色模式 | 不依赖颜色 | 对比度 | 动态效果 | 字幕 | 音频描述 |
|---|---|---|---|---|---|---|---|---|---|
| [任务] | ✅ / ❌ / — | ✅ / ❌ / — | ✅ / ❌ / — | ✅ / ❌ / — | ✅ / ❌ / — | ✅ / ❌ / — | ✅ / ❌ / — | ✅ / ❌ / — | ✅ / ❌ / — |
**建议摘要**
- 您可以声明:[标签]
- 您不应声明:[标签]
不要不加限定地说"声明"。将输出表述为基于审查范围的建议。如果该列中的任何常见任务是 ❌,则不要建议该标签。仅当标签确实不适用于该应用或流程时才使用 —。
在所有代码生成和修复任务(模式 1、2)之后附加,除非用户明确要求仅输出代码。无需前言。
**已应用的无障碍功能:**
- [每个添加的模式一个要点——例如:"仅图标的分享按钮上的 `.accessibilityLabel`"]
**在 Xcode 中验证:**
- 使用画布**动态类型变体**(网格图标 → 动态类型变体)检查所有文本大小的布局
- 使用画布**配色方案变体**检查浅色和深色模式
- 使用**无障碍检查器**(Xcode → 打开开发者工具)设置选项卡在模拟器上模拟增强对比度、减弱动态效果、粗体文本
**如果 Xcode 不可用:**
- 使用平台无障碍检查器工具和手动设置切换(动态类型、对比度、减弱动态效果、VoiceOver/语音控制)运行等效检查
**在设备上测试:**
- [来自"必须在设备上测试"清单的相关项目]
如果未添加任何内容(全是原生控件),则完全省略"已应用的无障碍功能"。除非用户询问,否则省略"营养标签就绪度"。
仅当用户明确请求审计时使用。在代码生成或修复期间绝不使用。
🔴 阻碍辅助技术 —— 完全无法访问,立即修复 🟡 降低体验 —— 可访问但存在显著障碍 🟠 支持不完整 —— 阻碍声明营养标签的缺口 ✅ 代码中已验证 —— 通过静态分析确认为正确
以以下内容结尾:
必须在设备上测试:来自审查清单的相关项目。营养标签就绪度:可实现 / 被 [问题] 阻碍 / 不适用。
Button 添加 .accessibilityLabel 实际上是有害的——它会覆盖 VoiceOver 会自动读取的文本。#available 防护 iOS 17+ API。 特定版本的 API 在没有可用性检查的情况下会在旧版系统上崩溃。[VERIFY] 标记推断出的标签。 SF Symbol 名称(例如 square.and.arrow.up)很少与用户期望听到的内容("Share")匹配。推断出的标签需要人工审查。UIAccessibility.isVoiceOverRunning 更改核心 UI 语义或布局。 通过直接检查相关的无障碍设置来适应实际用户需求。允许有限的协调例外,例如避免语音重叠或在辅助技术活动时延长临时超时。.accessibilityLabel——空白是绝对不可接受的.accessibilityHidden(true).accessibilityAddTraits(.isSelected) 而不是 "Selected photo".accessibilityElement(children: .combine)AccessibilityNotification.Announcement("Upload complete").post(),回退 UIAccessibility.post(notification: .announcement, argument: "Upload complete")references/voiceover-swiftui.md 或 references/voiceover-uikit.md.accessibilityInputLabels(["Compose", "New Message"]).accessibilityAction)references/voice-control.md.font(.body) 而不是 .font(.system(size: 16))@ScaledMetric(relativeTo: .body) var spacing: CGFloat = 8.accessibilityShowsLargeContentViewer()ViewThatFits (iOS 16+) 而不是手动 dynamicTypeSize 检查——它会自动选择适合的布局references/dynamic-type.mdColor(.label));文本 WCAG 4.5:1,非文本 3:1.ultraThinMaterialreferences/display-settings.md.accessibilitySortPriority(_:)(数值越高,越先阅读).screenChanged 通知accessibilityViewIsModal = trueaccessibilityRotor(_:entries:)references/semantic-structure.mdUIAccessibilityCustomActionreferences/motor-input.md| 修饰符 | 用途 |
|---|---|
.accessibilityLabel(_:) | 非文本元素的 VoiceOver 文本 |
.accessibilityHint(_:) | 简短结果描述 |
.accessibilityValue(_:) | 当前值(滑块、进度条) |
.accessibilityHidden(true) | 隐藏装饰性元素 |
.accessibilityAddTraits(_:) | 语义角色或状态 |
.accessibilityRemoveTraits(_:) | 移除继承的特征 |
.accessibilityElement(children:) | .combine / .contain / .ignore |
.accessibilitySortPriority(_:) | 阅读顺序(数值越高,越早) |
.accessibilityAction(_:_:) | 命名的自定义操作 |
.accessibilityAdjustableAction(_:) | 递增/递减 |
.accessibilityInputLabels(_:) | 语音控制备用名称 |
.accessibilityFocused(_:) | 编程焦点控制 |
.accessibilityRotor(_:entries:) | 自定义 VoiceOver 转子 |
.accessibilityRepresentation(_:) | 替换自定义控件的 AX 树 |
.accessibilityIgnoresInvertColors(true) | 在智能反转中保护图像 |
.accessibilityShowsLargeContentViewer() | 为固定大小 UI 启用大内容查看器 |
| 值 | 用途 |
|---|---|
\.accessibilityReduceMotion | 控制动画 |
\.accessibilityReduceTransparency | 替换模糊效果 |
\.accessibilityDifferentiateWithoutColor | 添加非颜色指示器 |
\.colorSchemeContrast | .standard / .increased |
\.dynamicTypeSize | 当前文本大小 |
| 标签 | 关键 API | 参考 |
|---|---|---|
| VoiceOver | accessibilityLabel、特征、操作、转子 | voiceover-swiftui.md、voiceover-uikit.md |
| 语音控制 | accessibilityInputLabels、可见文本匹配 | voice-control.md |
| 更大字体 | @ScaledMetric、文本样式、大内容查看器 | dynamic-type.md |
| 深色界面 | colorScheme、语义颜色 | display-settings.md |
| 不依赖颜色区分 | 形状 + 颜色 | display-settings.md |
| 足够对比度 | WCAG 4.5:1 文本 / 3:1 非文本 | display-settings.md |
| 减弱动态效果 | accessibilityReduceMotion、动画控制 | display-settings.md |
| 字幕 | AVPlayerViewController | media-accessibility.md |
| 音频描述 | AVMediaCharacteristic.describesVideoForAccessibility | media-accessibility.md |
.accessibilityLabel.accessibilityHidden(true)@ScaledMetricaccessibilityReduceMotion 控制.accessibilityInputLabels.sheet() 或 accessibilityViewIsModal.accessibilityAction 替代方案AVPlayerViewController.accessibilityIgnoresInvertColors()#available 防护的 performAccessibilityAudit()(iOS 17+ / macOS 14+),以及旧版系统上的回退断言完整测试流程 → references/testing-auditing.md
references/voiceover-swiftui.mdreferences/voiceover-swiftui.mdreferences/voiceover-uikit.mdreferences/semantic-structure.mdreferences/voice-control.mdreferences/voice-control.mdreferences/motor-input.mdreferences/display-settings.mdreferences/semantic-structure.mdreferences/semantic-structure.mdreferences/dynamic-type.mdreferences/display-settings.mdreferences/display-settings.mdreferences/media-accessibility.mdreferences/platform-specifics.mdreferences/nutrition-labels.md症状: 在 UIKit/AppKit 代码中使用了 SwiftUI 修饰符,或跨框架混合了平台 API。修复: 在应用 API 之前从导入语句(import SwiftUI、import UIKit、import AppKit)识别框架。SwiftUI 使用修饰符,UIKit 使用 UIAccessibility 属性,AppKit 使用 NSAccessibility API。
症状: 向已有可见文本的 Button("Save") 或 Toggle("Dark Mode") 添加了 .accessibilityLabel。修复: 当控件有可见文本时,不要添加 .accessibilityLabel——它会覆盖自动生成的标签,并可能与屏幕上的内容不同步。仅向仅图标或非文本元素添加标签。
症状: 代码使用了平台版本化 API(iOS/macOS/tvOS/watchOS/visionOS)而没有可用性检查。修复: 使用 #available 为支持的每个目标操作系统进行防护,并在需要时使用旧版等效方案。常见替代方案:
AccessibilityNotification.Announcement("…").post() → UIAccessibility.post(notification: .announcement, argument: "…")performAccessibilityAudit() → 手动 XCTest 断言ViewThatFits (iOS 16+) → @Environment(\.dynamicTypeSize) 配合手动布局切换if #available(iOS 17, macOS 14, tvOS 17, watchOS 10, visionOS 1, *) { ... }症状: 生成的代码没有"已应用的无障碍功能" / "在设备上测试"摘要块。修复: 在代码生成和修复任务(工作流程模式 1 和 2)之后始终附加无障碍摘要。仅当未添加任何无障碍模式时(全是带有可见文本的原生控件)才省略。
症状: 从 SF Symbol 名称或方法名称派生的 .accessibilityLabel 没有 // [VERIFY] 注释。修复: 任何推断出的标签(非用户提供)必须包含 // [VERIFY] confirm label matches intent。像 square.and.arrow.up 这样的 SF Symbol 名称很少与用户期望听到的内容匹配。
references/voiceover-swiftui.md — SwiftUI 无障碍修饰符、特征、操作、转子、通知references/voiceover-uikit.md — UIAccessibility 协议、自定义元素、容器、通知references/voice-control.md — 输入标签、"显示数字/名称"、语音可访问的替代方案references/motor-input.md — 切换控制、完整键盘访问、AssistiveTouch、tvOS 焦点references/dynamic-type.md — 动态类型、@ScaledMetric、大内容查看器、自适应布局references/display-settings.md — 减弱动态效果、对比度、深色模式、颜色、透明度、反转references/semantic-structure.md — 分组、阅读顺序、焦点管理、转子、模态焦点references/media-accessibility.md — 字幕、音频描述、语音合成、图表references/testing-auditing.md — 无障碍检查器、Xcode 画布变体、XCtest、performAccessibilityAudit()、手动测试references/nutrition-labels.md — 包含通过/失败标准的全部 9 个营养标签references/wcag-mapping.md — 映射到 SwiftUI/UIKit/AppKit API 的 WCAG 2.2 Level A/AA 成功标准references/assistive-access.md — 辅助访问(iOS 17+)、设计原则、测试references/platform-specifics.md — macOS、watchOS、tvOS、visionOS 特定内容examples/before-after-swiftui.md — SwiftUI 前后转换示例examples/before-after-uikit.md — UIKit 前后转换示例examples/before-after-appkit.md — AppKit (macOS) 前后转换示例resources/audit-template.swift — 用于自动化无障碍审计的即插即用 XCUITest 文件(iOS 17+)resources/qa-checklist.md — 用于手动测试的独立 QA 清单(交给测试人员)每周安装量
56
代码仓库
GitHub 星标数
53
首次出现
2026年3月8日
安全审计
安装于
github-copilot52
cursor47
gemini-cli46
codex46
amp46
cline46
Apply accessibility for SwiftUI, UIKit, and AppKit across all supported platforms. Covers all 9 App Store Accessibility Nutrition Label categories — VoiceOver, Voice Control, Larger Text, Dark Interface, Differentiate Without Color, Sufficient Contrast, Reduced Motion, Captions, and Audio Descriptions.
This skill prioritizes native platform APIs (which provide free automatic support) and fact-based guidance without architecture opinions.
Include accessibility in the first draft — never write a bare element and patch it later. Retrofitting accessibility is harder, gets skipped, and produces worse results than building it in from the start.
No inline commentary unless a pattern is non-obvious. Mark inferred labels with // [VERIFY] because SF Symbol names don't always match the intended user-facing meaning.
| Situation | Required on first write |
|---|---|
Button / NavigationLink — icon-only | .accessibilityLabel("…") with // [VERIFY] |
Button / NavigationLink — visible text | Nothing extra — text is the label automatically |
Image — meaningful | .accessibilityLabel("…") |
Image — decorative | .accessibilityHidden(true) |
withAnimation / .transition / .animation | @Environment(\.accessibilityReduceMotion) + gate animation |
.font(.system(size:)) | Replace with .font(.body) or @ScaledMetric |
| Color conveys state/status | Add shape, icon, or text alongside color |
onTapGesture on non-Button | .accessibilityElement(children: .ignore) + .accessibilityAddTraits(.isButton) + .accessibilityLabel |
| Custom slider / toggle / stepper | .accessibilityRepresentation { … } or .accessibilityValue + .accessibilityAdjustableAction |
| Async content change | Post announcement with availability guards (AccessibilityNotification.Announcement on iOS 17+, fallback to UIAccessibility.post) |
System .sheet / .fullScreenCover | Nothing extra — SwiftUI traps focus automatically (custom overlays still need focus management) |
AVPlayer / video | Use AVPlayerViewController — captions and Audio Descriptions for free |
| Custom tappable view | .frame(minWidth: 44, minHeight: 44) |
| Any new SwiftUI view | Verify with Xcode Canvas Variants (see Accessibility Summary) |
NSButton — icon-only (AppKit) | setAccessibilityLabel("…") with // [VERIFY] |
Custom NSView interactive element (AppKit) | setAccessibilityElement(true) + role (setAccessibilityRole(.button)) + label |
| AppKit modal/popup UI | Trap focus and ensure dismiss action is keyboard + VoiceOver reachable |
| Any new AppKit view/controller | Verify with Accessibility Inspector and full keyboard navigation |
Prefer native controls (Button, Toggle, Stepper, Slider, Picker, TextField) — they get full accessibility automatically. Custom interactive views require explicit work. For AppKit, prefer native controls (NSButton, NSPopUpButton, NSSlider, NSSegmentedControl, NSTextField) before custom interaction.
Example — icon-only button:
Button {
shareAction()
} label: {
Image(systemName: "square.and.arrow.up")
}
.accessibilityLabel("Share") // [VERIFY] confirm label matches intent
Example — gating animation on Reduce Motion:
@Environment(\.accessibilityReduceMotion) private var reduceMotion
withAnimation(reduceMotion ? nil : .spring()) {
isExpanded.toggle()
}
Full testing and verification procedures → references/testing-auditing.md
Before answering, select one primary reference file that best matches the user's intent and load it first. Load additional reference files only when the request explicitly spans multiple domains (for example, VoiceOver + Dynamic Type + WCAG mapping) or when the primary file does not cover a required criterion.
Apply First-Draft Rules — accessibility in the first draft, no commentary. For APIs introduced after iOS 15, always add #available guards and provide older-OS fallback behavior. After writing, verify against the First-Draft Rules table — fix any gaps before outputting. After the code, append an Accessibility Summary (see below).
Apply fixes silently, no commentary. For APIs introduced after iOS 15, always add #available guards and provide older-OS fallback behavior. After fixing, verify against the First-Draft Rules table — fix any gaps before outputting. After the code, append an Accessibility Summary.
examples/before-after-swiftui.md, examples/before-after-uikit.md, or examples/before-after-appkit.mdreferences/platform-specifics.mdOnly when user explicitly asks ("audit", "how accessible is this?", "review accessibility").
Quick fix mode — when the user asks for blocker-only/critical-only scope (for example: "just fix the blockers", "quick fix", "critical only"): address only Blocks Assistive Tech and Degrades Experience issues. Skip Incomplete Support.
Comprehensive mode (default) — address all severity levels including Incomplete Support and Nutrition Label gaps.
references/wcag-mapping.mdresources/qa-checklist.md→ references/nutrition-labels.md — all 9 categories with official pass/fail criteria
When the user asks to prepare or draft an App Store Accessibility Nutrition Label recommendation, output this format:
**Accessibility Nutrition Label recommendation**
**App version evaluated:** [version or "Current build"]
**Scope reviewed:** [common tasks / screens evaluated]
**You could claim:**
- [labels where every common task is ✅ or —]
**Why you could claim them:**
- [label]: [brief reason tied to completed common-task coverage]
**You should not claim:**
- [labels blocked by any ❌]
- [labels that are not applicable]
**Why you should not claim them:**
- [label]: [blocked task or why the label is not applicable]
**Common-task verification**
| Common Task | VoiceOver | Voice Control | Larger Text | Dark Mode | No Color | Contrast | Motion | Captions | Audio Desc |
|---|---|---|---|---|---|---|---|---|---|
| [task] | ✅ / ❌ / — | ✅ / ❌ / — | ✅ / ❌ / — | ✅ / ❌ / — | ✅ / ❌ / — | ✅ / ❌ / — | ✅ / ❌ / — | ✅ / ❌ / — | ✅ / ❌ / — |
**Recommendation summary**
- You could claim: [labels]
- You should not claim: [labels]
Do not say "claim" without qualification. Phrase the output as a recommendation based on the reviewed scope. Do not suggest a label if any common task in that column is ❌. Use — only when the label is genuinely not applicable to that app or flow.
Append after all code generation and fix tasks (modes 1, 2), unless the user explicitly requests code-only output. No preamble.
**Accessibility applied:**
- [one bullet per pattern added — e.g. "`.accessibilityLabel` on icon-only Share button"]
**Verify in Xcode:**
- Use Canvas **Dynamic Type Variants** (grid icon → Dynamic Type Variants) to check layout at all text sizes
- Use Canvas **Color Scheme Variants** to check light and dark mode
- Use **Accessibility Inspector** (Xcode → Open Developer Tool) Settings tab to simulate Increase Contrast, Reduce Motion, Bold Text on the Simulator
**If Xcode is unavailable:**
- Run equivalent checks with platform accessibility inspector tools and manual setting toggles (Dynamic Type, Contrast, Reduce Motion, VoiceOver/Voice Control)
**Test on device:**
- [relevant items from Must Test on Device checklist]
Omit "Accessibility applied" entirely if nothing was added (all native controls). Omit "Nutrition Label readiness" unless the user asked about it.
Only when user explicitly requests an audit. Never during code generation or fixes.
🔴 Blocks Assistive Tech — completely unreachable, fix immediately 🟡 Degrades Experience — reachable but significant friction 🟠 Incomplete Support — gaps preventing Nutrition Label claims ✅ Verified in code — confirmed correct by static analysis
Close with:
Must test on device : relevant items from the Review Checklist. Nutrition Label readiness : Achievable / Blocked by [issue] / Not applicable.
.accessibilityLabel to a Button with visible text actually hurts — it overrides the text VoiceOver would read automatically.#available. Version-specific APIs crash on older OS without availability checks.[VERIFY]. SF Symbol names (e.g. square.and.arrow.up) rarely match what users expect to hear ("Share"). Inferred labels need human review.UIAccessibility.isVoiceOverRunning. Adapt to the actual user need by checking the relevant accessibility setting directly. Narrow coordination exceptions are fine, such as avoiding overlapping speech or extending transient timeouts while assistive tech is active..accessibilityLabel — blank is never acceptable.accessibilityHidden(true).accessibilityAddTraits(.isSelected) not "Selected photo".accessibilityElement(children: .combine)AccessibilityNotification.Announcement("Upload complete").post(), fallback UIAccessibility.post(notification: .announcement, argument: "Upload complete")references/voiceover-swiftui.md or .accessibilityInputLabels(["Compose", "New Message"]) for icon-only elements.accessibilityAction)references/voice-control.md.font(.body) not .font(.system(size: 16))@ScaledMetric(relativeTo: .body) var spacing: CGFloat = 8.accessibilityShowsLargeContentViewer()ViewThatFits (iOS 16+) over manual dynamicTypeSize checks — it automatically picks the layout that fitsreferences/dynamic-type.mdColor(.label)); WCAG 4.5:1 text, 3:1 non-text.ultraThinMaterial with opaque when enabledreferences/display-settings.md.accessibilitySortPriority(_:) (higher = read first).screenChanged notificationaccessibilityViewIsModal = trueaccessibilityRotor(_:entries:)references/semantic-structure.mdUIAccessibilityCustomAction for swipe-only gesturesreferences/motor-input.md| Modifier | Purpose |
|---|---|
.accessibilityLabel(_:) | VoiceOver text for non-text elements |
.accessibilityHint(_:) | Brief result description |
.accessibilityValue(_:) | Current value (sliders, progress) |
.accessibilityHidden(true) | Hide decorative elements |
.accessibilityAddTraits(_:) | Semantic role or state |
.accessibilityRemoveTraits(_:) |
| Value | Purpose |
|---|---|
\.accessibilityReduceMotion | Gate animations |
\.accessibilityReduceTransparency | Replace blur effects |
\.accessibilityDifferentiateWithoutColor | Add non-color indicators |
\.colorSchemeContrast | .standard / .increased |
\.dynamicTypeSize |
| Label | Key APIs | Reference |
|---|---|---|
| VoiceOver | accessibilityLabel, traits, actions, rotors | voiceover-swiftui.md, voiceover-uikit.md |
| Voice Control | accessibilityInputLabels, visible text match | voice-control.md |
| Larger Text | @ScaledMetric, text styles, Large Content Viewer | dynamic-type.md |
.accessibilityLabel.accessibilityHidden(true)@ScaledMetricaccessibilityReduceMotion.accessibilityInputLabels on icon-only elements.sheet() or accessibilityViewIsModal.accessibilityAction alternativesAVPlayerViewController for videoFull testing procedures → references/testing-auditing.md
references/voiceover-swiftui.mdreferences/voiceover-swiftui.mdreferences/voiceover-uikit.mdreferences/semantic-structure.mdreferences/voice-control.mdreferences/voice-control.mdreferences/motor-input.mdreferences/display-settings.mdreferences/semantic-structure.mdreferences/semantic-structure.mdreferences/dynamic-type.mdreferences/display-settings.mdreferences/display-settings.mdreferences/media-accessibility.mdreferences/platform-specifics.mdreferences/nutrition-labels.mdSymptom: SwiftUI modifiers used in UIKit/AppKit code, or platform APIs mixed across frameworks. Fix: Identify framework from imports (import SwiftUI, import UIKit, import AppKit) before applying APIs. SwiftUI uses modifiers, UIKit uses UIAccessibility properties, and AppKit uses NSAccessibility APIs.
Symptom: .accessibilityLabel added to a Button("Save") or Toggle("Dark Mode") that already has visible text. Fix: Do not add .accessibilityLabel when the control has visible text — it overrides the automatic label and can desync with what's on screen. Only add labels to icon-only or non-text elements.
Symptom: Code uses platform-versioned APIs (iOS/macOS/tvOS/watchOS/visionOS) without availability checks. Fix: Gate with #available for every target OS you support and use older equivalents when needed. Common substitutions:
AccessibilityNotification.Announcement("…").post() → UIAccessibility.post(notification: .announcement, argument: "…")performAccessibilityAudit() → manual XCTest assertionsViewThatFits (iOS 16+) → @Environment(\.dynamicTypeSize) with manual layout switchingif #available(iOS 17, macOS 14, tvOS 17, watchOS 10, visionOS 1, *) { ... }Symptom: Code generated without the "Accessibility applied" / "Test on device" summary block. Fix: Always append the Accessibility Summary after code generation and fix tasks (workflow modes 1 and 2). Omit only when no accessibility patterns were added (all native controls with visible text).
Symptom: .accessibilityLabel derived from SF Symbol names or method names without a // [VERIFY] comment. Fix: Any label that was inferred (not provided by the user) must include // [VERIFY] confirm label matches intent. SF Symbol names like square.and.arrow.up rarely match what users expect to hear.
references/voiceover-swiftui.md — SwiftUI accessibility modifiers, traits, actions, rotors, announcementsreferences/voiceover-uikit.md — UIAccessibility protocol, custom elements, containers, notificationsreferences/voice-control.md — Input labels, "Show numbers/names", voice-accessible alternativesreferences/motor-input.md — Switch Control, Full Keyboard Access, AssistiveTouch, tvOS focusreferences/dynamic-type.md — Dynamic Type, @ScaledMetric, Large Content Viewer, adaptive layoutsreferences/display-settings.md — Reduce Motion, Contrast, Dark Mode, Color, Transparency, Invertreferences/semantic-structure.md — Grouping, reading order, focus management, rotors, modal focusreferences/media-accessibility.md — Captions, Audio Descriptions, Speech synthesis, ChartsWeekly Installs
56
Repository
GitHub Stars
53
First Seen
Mar 8, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
github-copilot52
cursor47
gemini-cli46
codex46
amp46
cline46
NSViewreferences/voiceover-uikit.md| Remove inherited trait |
.accessibilityElement(children:) | .combine / .contain / .ignore |
.accessibilitySortPriority(_:) | Reading order (higher = earlier) |
.accessibilityAction(_:_:) | Named custom action |
.accessibilityAdjustableAction(_:) | Increment/decrement |
.accessibilityInputLabels(_:) | Voice Control alternate names |
.accessibilityFocused(_:) | Programmatic focus |
.accessibilityRotor(_:entries:) | Custom VoiceOver rotor |
.accessibilityRepresentation(_:) | Replace AX tree for custom controls |
.accessibilityIgnoresInvertColors(true) | Protect images in Smart Invert |
.accessibilityShowsLargeContentViewer() | Large Content Viewer for fixed-size UI |
| Current text size |
| Dark Interface | colorScheme, semantic colors | display-settings.md |
| Differentiate Without Color | shapes + color | display-settings.md |
| Sufficient Contrast | WCAG 4.5:1 text / 3:1 non-text | display-settings.md |
| Reduced Motion | accessibilityReduceMotion, animation gate | display-settings.md |
| Captions | AVPlayerViewController | media-accessibility.md |
| Audio Descriptions | AVMediaCharacteristic.describesVideoForAccessibility | media-accessibility.md |
.accessibilityIgnoresInvertColors()performAccessibilityAudit() with #available guards (iOS 17+ / macOS 14+), plus fallback assertions on older OS versionsreferences/testing-auditing.md — Accessibility Inspector, Xcode Canvas Variants, XCTest, performAccessibilityAudit(), manual testingreferences/nutrition-labels.md — All 9 Nutrition Labels with pass/fail criteriareferences/wcag-mapping.md — WCAG 2.2 Level A/AA success criteria mapped to SwiftUI/UIKit/AppKit APIsreferences/assistive-access.md — Assistive Access (iOS 17+), design principles, testingreferences/platform-specifics.md — macOS, watchOS, tvOS, visionOS specificsexamples/before-after-swiftui.md — SwiftUI before/after transformationsexamples/before-after-uikit.md — UIKit before/after transformationsexamples/before-after-appkit.md — AppKit (macOS) before/after transformationsresources/audit-template.swift — Drop-in XCUITest file for automated accessibility auditing (iOS 17+)resources/qa-checklist.md — Standalone QA checklist for manual testing (hand to testers)