{"id":"d2032bde-41e7-4ff2-ade0-0cb33cc9977a","shortId":"CuZ8Kv","kind":"skill","title":"ios-accessibility","tagline":"Implement, review, or improve accessibility in iOS/macOS apps with SwiftUI and UIKit. Use when adding VoiceOver, Voice Control, Switch Control, or Full Keyboard Access support; when working with accessibility labels, hints, values, traits, or accessibilityInputLabels; when groupi","description":"# iOS Accessibility — SwiftUI and UIKit\n\nEvery user-facing view must be usable with VoiceOver, Switch Control, Voice Control, Full Keyboard Access, and other assistive technologies. This skill covers the patterns and APIs required to build accessible iOS apps.\n\n## Contents\n\n- [Core Principles](#core-principles)\n- [How VoiceOver Reads Elements](#how-voiceover-reads-elements)\n- [SwiftUI Accessibility Modifiers](#swiftui-accessibility-modifiers)\n- [Focus Management](#focus-management)\n- [Dynamic Type](#dynamic-type)\n- [Custom Rotors](#custom-rotors)\n- [System Accessibility Preferences](#system-accessibility-preferences)\n- [Decorative Content](#decorative-content)\n- [Voice Control](#voice-control)\n- [Switch Control](#switch-control)\n- [Full Keyboard Access](#full-keyboard-access)\n- [Assistive Access (iOS 18+)](#assistive-access-ios-18)\n- [UIKit Accessibility Patterns](#uikit-accessibility-patterns)\n- [Accessibility Custom Content](#accessibility-custom-content)\n- [Testing Accessibility](#testing-accessibility)\n- [Common Mistakes](#common-mistakes)\n- [Review Checklist](#review-checklist)\n- [References](#references)\n\n---\n\n## Core Principles\n\n1. Every interactive element MUST have an accessible label. If no visible text exists, add `.accessibilityLabel`.\n2. Every custom control MUST have correct traits via `.accessibilityAddTraits` (never direct assignment).\n3. Decorative images MUST be hidden from assistive technologies.\n4. Sheet and dialog dismissals MUST return VoiceOver focus to the trigger element.\n5. All tap targets MUST be at least 44x44 points.\n6. Dynamic Type MUST be supported everywhere (system fonts, `@ScaledMetric`, adaptive layouts).\n7. No information conveyed by color alone -- always provide text or icon alternatives.\n8. System accessibility preferences MUST be respected: Reduce Motion, Reduce Transparency, Bold Text, Increase Contrast.\n\n## How VoiceOver Reads Elements\n\nVoiceOver reads element properties in a fixed, non-configurable order:\n\n**Label -> Value -> Trait -> Hint**\n\nDesign your labels, values, and hints with this reading order in mind.\n\n## SwiftUI Accessibility Modifiers\n\nSee [references/a11y-patterns.md](references/a11y-patterns.md) for detailed SwiftUI modifier examples (labels, hints, traits, grouping, custom controls, adjustable actions, and custom actions).\n\n## Focus Management\n\nFocus management is where most apps fail. When a sheet, alert, or popover is dismissed, VoiceOver focus MUST return to the element that triggered it.\n\n### @AccessibilityFocusState (iOS 15+)\n\n`@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.\n\n```swift\nstruct ContentView: View {\n    @State private var showSheet = false\n    @AccessibilityFocusState private var focusOnTrigger: Bool\n\n    var body: some View {\n        Button(\"Open Settings\") { showSheet = true }\n            .accessibilityFocused($focusOnTrigger)\n            .sheet(isPresented: $showSheet) {\n                SettingsSheet()\n                    .onDisappear {\n                        // Slight delay allows the transition to complete before moving focus\n                        Task { @MainActor in\n                            try? await Task.sleep(for: .milliseconds(100))\n                            focusOnTrigger = true\n                        }\n                    }\n            }\n    }\n}\n```\n\n### Multi-Target Focus with Enum\n\n```swift\nenum A11yFocus: Hashable {\n    case nameField\n    case emailField\n    case submitButton\n}\n\nstruct FormView: View {\n    @AccessibilityFocusState private var focus: A11yFocus?\n\n    var body: some View {\n        Form {\n            TextField(\"Name\", text: $name)\n                .accessibilityFocused($focus, equals: .nameField)\n            TextField(\"Email\", text: $email)\n                .accessibilityFocused($focus, equals: .emailField)\n            Button(\"Submit\") { validate() }\n                .accessibilityFocused($focus, equals: .submitButton)\n        }\n    }\n\n    func validate() {\n        if name.isEmpty {\n            focus = .nameField // Move VoiceOver to the invalid field\n        }\n    }\n}\n```\n\n### Custom Modals\n\nCustom overlay views need the `.isModal` trait to trap VoiceOver focus and an escape action for dismissal:\n\n```swift\nCustomDialog()\n    .accessibilityAddTraits(.isModal)\n    .accessibilityAction(.escape) { dismiss() }\n```\n\n### Accessibility Notifications (UIKit)\n\nWhen you need to announce changes or move focus imperatively in UIKit contexts:\n\n```swift\n// Announce a status change (e.g., \"Item deleted\", \"Upload complete\")\nUIAccessibility.post(notification: .announcement, argument: \"Upload complete\")\n\n// Partial screen update -- move focus to a specific element\nUIAccessibility.post(notification: .layoutChanged, argument: targetView)\n\n// Full screen transition -- move focus to the new screen\nUIAccessibility.post(notification: .screenChanged, argument: newScreenView)\n```\n\n## Dynamic Type\n\nSee [references/a11y-patterns.md](references/a11y-patterns.md) for Dynamic Type and adaptive layout examples, including @ScaledMetric and minimum tap target patterns.\n\n## Custom Rotors\n\nRotors let VoiceOver users quickly navigate to specific content types. Add custom rotors for content-heavy screens. See [references/a11y-patterns.md](references/a11y-patterns.md) for complete rotor examples.\n\n## System Accessibility Preferences\n\nAlways respect these environment values:\n\n```swift\n@Environment(\\.accessibilityReduceMotion) var reduceMotion\n@Environment(\\.accessibilityReduceTransparency) var reduceTransparency\n@Environment(\\.colorSchemeContrast) var contrast         // .standard or .increased\n@Environment(\\.legibilityWeight) var legibilityWeight    // .regular or .bold\n```\n\n### Reduce Motion\n\nReplace movement-based animations with crossfades or no animation:\n\n```swift\nwithAnimation(reduceMotion ? nil : .spring()) {\n    showContent.toggle()\n}\ncontent.transition(reduceMotion ? .opacity : .slide)\n```\n\n### Reduce Transparency, Increase Contrast, Bold Text\n\n```swift\n// Solid backgrounds when transparency is reduced\n.background(reduceTransparency ? Color(.systemBackground) : Color(.systemBackground).opacity(0.85))\n\n// Stronger colors when contrast is increased\n.foregroundStyle(contrast == .increased ? .primary : .secondary)\n\n// Bold weight when system bold text is enabled\n.fontWeight(legibilityWeight == .bold ? .bold : .regular)\n```\n\n## Decorative Content\n\n```swift\n// Decorative images: hidden from VoiceOver\nImage(decorative: \"background-pattern\")\nImage(\"visual-divider\").accessibilityHidden(true)\n\n// Icon next to text: Label handles this automatically\nLabel(\"Settings\", systemImage: \"gear\")\n\n// Icon-only buttons: MUST have an accessibility label\nButton(action: { }) {\n    Image(systemName: \"gear\")\n}\n.accessibilityLabel(\"Settings\")\n```\n\n## Voice Control\n\nVoice Control relies on accessibility labels to generate spoken tap targets. If a label is missing or unspeakable, Voice Control cannot target the element.\n\n- Every interactive element MUST have a speakable accessibility label (no emoji-only, no symbol-only).\n- Labels must be unique within the visible screen — duplicate labels force users to disambiguate with overlay numbers.\n- When the primary label is long or awkward to speak, provide shorter alternatives with `accessibilityInputLabels` (iOS 14+). Voice Control and Full Keyboard Access use these. List alternatives in descending order of importance.\n- Test with Voice Control enabled: say \"Show Names\" and \"Show Numbers\" to verify all interactive elements are targetable.\n\nSee [references/a11y-patterns.md](references/a11y-patterns.md) for `accessibilityInputLabels` examples and speakable label guidelines.\n\n## Switch Control\n\nSwitch Control scans accessibility elements sequentially in reading order. Proper grouping and custom actions are critical for usability.\n\n- Group related content with `.accessibilityElement(children: .combine)` to reduce scan stops.\n- Every scan target should be meaningful and actionable. Decorative elements hidden from VoiceOver are also hidden from Switch Control.\n- Switch Control users cannot perform swipe-to-delete, long-press, or multi-finger gestures. Expose these interactions as `.accessibilityAction(named:)` custom actions instead — Switch Control presents them as a menu.\n- Custom controls with non-standard hit areas should ensure `accessibilityFrame` accurately reflects the tappable region (for point scanning mode).\n\nSee [references/a11y-patterns.md](references/a11y-patterns.md) for custom action and grouping examples.\n\n## Full Keyboard Access\n\nFull Keyboard Access (iOS 15+) provides Tab/Shift-Tab navigation, arrow keys, Space/Enter activation, and Escape for dismissal. Standard SwiftUI controls are focusable by default.\n\n- Tab order follows the accessibility element order.\n- Use `.focusable()` (iOS 17+) to make custom views participate in the focus system. The `focusable(_:interactions:)` variant controls whether the view supports `.activate`, `.edit`, or both.\n- Use `@FocusState` to track and programmatically move keyboard focus.\n- Add `.keyboardShortcut()` to frequently used actions. Do not override system-defined shortcuts (Cmd+C, Cmd+V, Cmd+Tab, etc.).\n- The system draws a focus ring automatically. Use `@FocusState` + `.focused($isFocused)` if a custom view needs to adjust its appearance when focused.\n\nSee [references/a11y-patterns.md](references/a11y-patterns.md) for `.focusable()`, `FocusInteractions`, keyboard shortcut, and multi-field focus examples.\n\n## Assistive Access (iOS 18+)\n\nAssistive Access provides a simplified interface for users with cognitive disabilities. Apps should support this mode:\n\n```swift\n// Check if Assistive Access is active (iOS 18+)\n@Environment(\\.accessibilityAssistiveAccessEnabled) var isAssistiveAccessEnabled\n\nvar body: some View {\n    if isAssistiveAccessEnabled {\n        SimplifiedContentView()\n    } else {\n        FullContentView()\n    }\n}\n```\n\nKey guidelines:\n- Reduce visual complexity: fewer controls, larger tap targets, simpler navigation\n- Use clear, literal language for labels and instructions\n- Minimize the number of choices presented at once\n- Test with Assistive Access enabled in Settings > Accessibility > Assistive Access\n\n## UIKit Accessibility Patterns\n\nWhen working with UIKit views:\n\n- Set `isAccessibilityElement = true` on meaningful custom views.\n- Set `accessibilityLabel` on all interactive elements without visible text.\n- Use `.insert()` and `.remove()` for trait modification (not direct assignment).\n- Set `accessibilityViewIsModal = true` on custom overlay views to trap focus.\n- Post `.announcement` for transient status messages.\n- Post `.layoutChanged` with a target view for partial screen updates.\n- Post `.screenChanged` for full screen transitions.\n\n```swift\n// UIKit trait modification\ncustomButton.accessibilityTraits.insert(.button)\ncustomButton.accessibilityTraits.remove(.staticText)\n\n// Modal overlay\noverlayView.accessibilityViewIsModal = true\n```\n\n## Accessibility Custom Content\n\nSee [references/a11y-patterns.md](references/a11y-patterns.md) for UIKit accessibility patterns and custom content examples.\n\n```swift\nProductRow(product: product)\n    .accessibilityCustomContent(\"Price\", product.formattedPrice)\n    .accessibilityCustomContent(\"Rating\", \"\\(product.rating) out of 5\")\n    .accessibilityCustomContent(\n        \"Availability\",\n        product.inStock ? \"In stock\" : \"Out of stock\",\n        importance: .high  // .high reads automatically with the element\n    )\n```\n\n## Testing Accessibility\n\n### Manual Testing\n\n- **Accessibility Inspector** (Xcode > Open Developer Tool): Audit views for missing labels, traits, and contrast issues. Run audits against the Simulator or connected device.\n- **VoiceOver testing**: Enable in Settings > Accessibility > VoiceOver. Navigate every screen with swipe gestures.\n- **Voice Control testing**: Enable in Settings > Accessibility > Voice Control. Say \"Show Names\" and \"Show Numbers\" to verify all elements are targetable.\n- **Full Keyboard Access testing**: Enable in Settings > Accessibility > Keyboards > Full Keyboard Access. Tab through every screen and verify all interactive elements receive focus.\n- **Switch Control testing**: Enable in Settings > Accessibility > Switch Control. Verify scan order is logical and custom actions appear for gesture-based interactions.\n- **Dynamic Type**: Test with all text sizes in Settings > Accessibility > Display & Text Size > Larger Text.\n\n### Automated Testing with XCTest\n\nUse `XCUIElement` accessibility attributes to write UI tests that verify accessibility properties:\n\n```swift\nfunc testProductRowAccessibility() throws {\n    let app = XCUIApplication()\n    app.launch()\n\n    let productCell = app.cells[\"product-organic-apples\"]\n    XCTAssertTrue(productCell.exists)\n    XCTAssertTrue(productCell.isEnabled)\n\n    // Verify the label is set and meaningful\n    XCTAssertFalse(productCell.label.isEmpty)\n\n    // Verify a specific element has the expected label\n    let favoriteButton = productCell.buttons[\"Favorite\"]\n    XCTAssertTrue(favoriteButton.exists)\n    XCTAssertTrue(favoriteButton.isEnabled)\n}\n```\n\nKey `XCUIElementAttributes` properties for accessibility verification: `label`, `identifier`, `value`, `isEnabled`, `hasFocus`, `isSelected`, `placeholderValue`, `title`.\n\nTest dismissal focus restoration:\n\n```swift\nfunc testSheetDismissReturnsFocus() throws {\n    let app = XCUIApplication()\n    app.launch()\n\n    let triggerButton = app.buttons[\"Open Settings\"]\n    triggerButton.tap()\n\n    // Dismiss the sheet\n    let doneButton = app.buttons[\"Done\"]\n    doneButton.tap()\n\n    // Verify focus returns to trigger (in accessibility-focused testing)\n    XCTAssertTrue(triggerButton.hasFocus)\n}\n```\n\n## Common Mistakes\n\n1. **Direct trait assignment**: `.accessibilityTraits(.isButton)` overwrites all existing traits. Use `.accessibilityAddTraits(.isButton)`.\n2. **Missing focus restoration**: Dismissing sheets without returning VoiceOver focus to the trigger element.\n3. **Ungrouped list rows**: Multiple text elements per row create excessive swipe stops. Use `.accessibilityElement(children: .combine)`.\n4. **Redundant trait in labels**: `.accessibilityLabel(\"Settings button\")` reads as \"Settings button, button.\" Omit the type.\n5. **Missing labels on icon-only buttons**: Every `Image`-only button MUST have `.accessibilityLabel`.\n6. **Ignoring Reduce Motion**: Always check `accessibilityReduceMotion` before movement animations.\n7. **Fixed font sizes**: `.font(.system(size: 16))` ignores Dynamic Type. Use `.font(.body)` or similar text styles.\n8. **Small tap targets**: Icons without `frame(minWidth: 44, minHeight: 44)` and `.contentShape()`.\n9. **Color as sole indicator**: Red/green for error/success without text or icon alternatives.\n10. **Missing `.isModal` on overlays**: Custom modals without `.accessibilityAddTraits(.isModal)` let VoiceOver escape.\n\n## Review Checklist\n\nFor every user-facing view, verify:\n\n- [ ] Every interactive element has an accessible label\n- [ ] Custom controls use correct traits via `.accessibilityAddTraits`\n- [ ] Decorative images are hidden (`Image(decorative:)` or `.accessibilityHidden(true)`)\n- [ ] List rows group content with `.accessibilityElement(children: .combine)`\n- [ ] Sheets and dialogs return focus to the trigger on dismiss\n- [ ] Custom overlays have `.isModal` trait and escape action\n- [ ] All tap targets are at least 44x44 points\n- [ ] Dynamic Type supported (`@ScaledMetric`, system fonts, adaptive layouts)\n- [ ] Reduce Motion respected (no movement animations when enabled)\n- [ ] Reduce Transparency respected (solid backgrounds when enabled)\n- [ ] Increase Contrast respected (stronger foreground colors)\n- [ ] No information conveyed by color alone\n- [ ] Custom actions provided for swipe-to-reveal and context menu features\n- [ ] Icon-only buttons have labels\n- [ ] Heading traits set on section headers\n- [ ] Custom accessibility types and notification payloads are `Sendable` when passed across concurrency boundaries\n- [ ] Labels are speakable and unique for Voice Control (no emoji-only or duplicate labels on screen)\n- [ ] `accessibilityInputLabels` provided for elements with long or awkward primary labels\n- [ ] Gesture-based interactions (swipe-to-delete, long-press) have accessibility custom action equivalents for Switch Control\n- [ ] Custom views use `.focusable()` when they should participate in Full Keyboard Access navigation\n- [ ] System keyboard shortcuts are not overridden\n\n## References\n\n- Detailed patterns: [references/a11y-patterns.md](references/a11y-patterns.md)","tags":["ios","accessibility","swift","skills","dpearson2699","agent-skills","ai-coding","apple","claude-code","codex-skills","cursor-skills","ios-development"],"capabilities":["skill","source-dpearson2699","skill-ios-accessibility","topic-accessibility","topic-agent-skills","topic-ai-coding","topic-apple","topic-claude-code","topic-codex-skills","topic-cursor-skills","topic-ios","topic-ios-development","topic-liquid-glass","topic-localization","topic-mapkit"],"categories":["swift-ios-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/dpearson2699/swift-ios-skills/ios-accessibility","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add dpearson2699/swift-ios-skills","source_repo":"https://github.com/dpearson2699/swift-ios-skills","install_from":"skills.sh"}},"qualityScore":"0.684","qualityRationale":"deterministic score 0.68 from registry signals: · indexed on github topic:agent-skills · 468 github stars · SKILL.md body (16,688 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-04-22T06:53:43.731Z","embedding":null,"createdAt":"2026-04-18T20:32:43.098Z","updatedAt":"2026-04-22T06:53:43.731Z","lastSeenAt":"2026-04-22T06:53:43.731Z","tsv":"'0.85':724 '1':188,1589 '10':1718 '100':452 '14':872 '15':371,1035 '16':1681 '17':1064 '18':149,154,1155,1180 '2':204,1602 '3':217,1616 '4':226,1633 '44':1700,1702 '44x44':247,1795 '5':239,1336,1649 '6':249,1664 '7':261,1674 '8':274,1692 '9':1705 'a11yfocus':463,478 'access':3,8,27,32,42,62,77,96,100,118,122,141,145,147,152,156,160,162,166,170,173,195,276,321,383,545,652,787,802,829,878,921,1030,1033,1058,1153,1157,1176,1225,1229,1231,1233,1310,1318,1354,1357,1385,1399,1416,1421,1425,1443,1469,1481,1489,1539,1582,1745,1857,1908,1926 'accessibility-custom-cont':165 'accessibility-focus':1581 'accessibilityact':542,987 'accessibilityaddtrait':213,540,1600,1726,1753 'accessibilityassistiveaccessen':1182 'accessibilitycustomcont':1328,1331,1337 'accessibilityel':940,1630,1768 'accessibilityfocus':427,488,496,503 'accessibilityfocusst':369,372,413,474 'accessibilityfram':1009 'accessibilityhidden':766,1761 'accessibilityinputlabel':38,870,910,1886 'accessibilitylabel':203,794,1248,1638,1663 'accessibilityreducemot':661,1670 'accessibilityreducetranspar':665 'accessibilitytrait':1593 'accessibilityviewismod':1267 'accur':1010 'across':1866 'action':338,341,535,790,931,954,990,1024,1101,1453,1788,1833,1910 'activ':1042,1083,1178 'ad':18 'adapt':259,614,1803 'add':202,636,1096 'adjust':337,1133 'alert':354 'allow':436 'alon':267,1831 'also':961 'altern':273,868,882,1717 'alway':268,654,1668 'anim':688,693,1673,1810 'announc':552,562,573,1277 'api':73 'app':11,79,349,1167,1496,1558 'app.buttons':1563,1572 'app.cells':1501 'app.launch':1498,1560 'appear':1135,1454 'appl':1505 'area':1006 'argument':574,589,603 'arrow':1039 'assign':216,1265,1592 'assist':65,146,151,224,1152,1156,1175,1224,1230 'assistive-access-io':150 'attribut':1482 'audit':1363,1373 'autom':1475 'automat':775,1122,1349 'avail':1338 'await':448 'awkward':863,1893 'background':712,717,760,1817 'background-pattern':759 'base':687,1458,1898 'bodi':419,480,1186,1687 'bold':285,681,708,736,740,746,747 'bool':388,417 'boundari':1868 'build':76 'button':422,500,783,789,1303,1640,1644,1645,1656,1660,1847 'c':1110 'cannot':818,969 'case':465,467,469 'chang':553,565 'check':1173,1669 'checklist':180,183,1732 'children':941,1631,1769 'choic':1218 'clear':1207 'cmd':1109,1111,1113 'cognit':1165 'color':266,719,721,726,1706,1825,1830 'colorschemecontrast':669 'combin':942,1632,1770 'common':174,177,1587 'common-mistak':176 'complet':440,570,576,648 'complex':1198 'concurr':1867 'configur':302 'connect':1378 'content':80,125,128,164,168,634,641,750,938,1312,1322,1766 'content-heavi':640 'content.transition':700 'contentshap':1704 'contentview':406 'context':560,1841 'contrast':288,671,707,728,732,1370,1821 'control':21,23,57,59,130,133,135,138,207,336,797,799,817,874,891,917,919,965,967,993,1000,1049,1078,1200,1394,1401,1438,1445,1748,1876,1914 'convey':264,1828 'core':81,84,186 'core-principl':83 'correct':210,1750 'cover':69 'creat':1625 'critic':933 'crossfad':690 'current':382 'custom':112,115,163,167,206,335,340,519,521,624,637,930,989,999,1023,1067,1129,1245,1270,1311,1321,1452,1723,1747,1781,1832,1856,1909,1915 'custom-rotor':114 'custombutton.accessibilitytraits.insert':1302 'custombutton.accessibilitytraits.remove':1304 'customdialog':539 'decor':124,127,218,749,752,758,955,1754,1759 'decorative-cont':126 'default':1053 'defin':1107 'delay':435 'delet':568,974,1903 'descend':884 'design':308 'detail':327,1935 'develop':1361 'devic':1379 'dialog':229,1773 'direct':215,1264,1590 'disabl':1166 'disambigu':852 'dismiss':230,358,537,544,1046,1550,1567,1606,1780 'display':1470 'divid':765 'done':1573 'donebutton':1571 'donebutton.tap':1574 'draw':1118 'duplic':847,1882 'dynam':107,110,250,605,611,1460,1683,1797 'dynamic-typ':109 'e.g':566 'edit':1084 'element':89,94,191,238,292,295,365,585,821,824,903,922,956,1059,1252,1352,1411,1434,1522,1615,1622,1742,1889 'els':1192 'email':493,495 'emailfield':468,499 'emoji':833,1879 'emoji-on':832,1878 'enabl':743,892,1226,1382,1396,1418,1440,1812,1819 'ensur':1008 'enum':398,460,462 'environ':657,660,664,668,675,1181 'equal':490,498,505 'equival':1911 'error/success':1712 'escap':534,543,1044,1730,1787 'etc':1115 'everi':46,189,205,822,947,1388,1428,1657,1734,1740 'everywher':255 'exampl':330,616,650,911,1027,1151,1323 'excess':1626 'exist':201,1597 'expect':1525 'expos':983 'face':49,1737 'fail':350 'fals':412 'favorit':1530 'favoritebutton':1528 'favoritebutton.exists':1532 'favoritebutton.isenabled':1534 'featur':1843 'fewer':1199 'field':518,1149 'finger':981 'fix':299,1675 'focus':102,105,234,342,344,360,384,393,403,443,458,477,489,497,504,511,531,556,581,595,1051,1062,1072,1075,1095,1120,1125,1137,1142,1150,1275,1436,1551,1576,1583,1604,1611,1775,1918 'focus-manag':104 'focusinteract':1143 'focusontrigg':416,428,453 'focusst':1088,1124 'follow':1056 'font':257,1676,1678,1686,1802 'fontweight':744 'forc':849 'foreground':1824 'foregroundstyl':731 'form':483 'formview':472 'frame':1698 'frequent':1099 'full':25,60,139,143,591,876,1028,1031,1295,1414,1423,1924 'full-keyboard-access':142 'fullcontentview':1193 'func':507,1492,1554 'gear':779,793 'generat':805 'gestur':982,1392,1457,1897 'gesture-bas':1456,1896 'group':334,928,936,1026,1765 'groupi':40 'guidelin':915,1195 'handl':773 'hasfocus':1545 'hashabl':397,464 'head':1850 'header':1855 'heavi':642 'hidden':222,754,957,962,1757 'high':1346,1347 'hint':34,307,313,332 'hit':1005 'how-voiceover-reads-el':90 'icon':272,768,781,1654,1696,1716,1845 'icon-on':780,1653,1844 'identifi':1542 'ignor':1665,1682 'imag':219,753,757,762,791,1658,1755,1758 'imper':557 'implement':4 'import':887,1345 'improv':7 'includ':617 'increas':287,674,706,730,733,1820 'indic':1709 'inform':263,1827 'insert':1257 'inspector':1358 'instead':991 'instruct':1213 'interact':190,823,902,985,1076,1251,1433,1459,1741,1899 'interfac':1161 'invalid':517 'io':2,41,78,148,153,370,871,1034,1063,1154,1179 'ios-access':1 'ios/macos':10 'isaccessibilityel':1241 'isassistiveaccessen':1184,1190 'isbutton':1594,1601 'isen':1544 'isfocus':1126 'ismod':526,541,1720,1727,1784 'ispres':430 'isselect':1546 'issu':1371 'item':567 'key':1040,1194,1535 'keyboard':26,61,140,144,877,1029,1032,1094,1144,1415,1422,1424,1925,1929 'keyboardshortcut':1097 'label':33,196,304,310,331,772,776,788,803,811,830,839,848,859,914,1211,1367,1512,1526,1541,1637,1651,1746,1849,1869,1883,1895 'languag':1209 'larger':1201,1473 'layout':260,615,1804 'layoutchang':588,1283 'least':246,1794 'legibilityweight':676,678,745 'let':627,1495,1499,1527,1557,1561,1570,1728 'list':881,1618,1763 'liter':1208 'logic':1450 'long':861,976,1891,1905 'long-press':975,1904 'mainactor':445 'make':1066 'manag':103,106,343,345 'manual':1355 'meaning':952,1244,1516 'menu':998,1842 'messag':1281 'millisecond':451 'mind':319 'minheight':1701 'minim':1214 'minimum':620 'minwidth':1699 'miss':813,1366,1603,1650,1719 'mistak':175,178,1588 'modal':520,1306,1724 'mode':1018,1171 'modif':1262,1301 'modifi':97,101,322,329 'motion':282,683,1667,1806 'move':442,513,555,580,594,1093 'movement':686,1672,1809 'movement-bas':685 'multi':401,456,980,1148 'multi-field':1147 'multi-fing':979 'multi-target':400,455 'multipl':1620 'must':51,192,208,220,231,243,252,278,361,784,825,840,1661 'name':485,487,895,988,1404 'name.isempty':510 'namefield':466,491,512 'navig':631,1038,1205,1387,1927 'need':524,550,1131 'never':214 'new':598 'newscreenview':604 'next':769 'nil':697 'non':301,1003 'non-configur':300 'non-standard':1002 'notif':546,572,587,601,1860 'number':855,898,1216,1407 'omit':1646 'ondisappear':433 'opac':702,723 'open':423,1360,1564 'option':396 'order':303,317,885,926,1055,1060,1448 'organ':1504 'overlay':522,854,1271,1307,1722,1782 'overlayview.accessibilityviewismodal':1308 'overrid':1104 'overridden':1933 'overwrit':1595 'partial':577,1289 'particip':1069,1922 'pass':1865 'pattern':71,157,161,623,761,1234,1319,1936 'payload':1861 'per':1623 'perform':970 'placeholdervalu':1547 'point':248,1016,1796 'popov':356 'post':1276,1282,1292 'prefer':119,123,277,653 'present':994,1219 'press':977,1906 'price':1329 'primari':734,858,1894 'principl':82,85,187 'privat':409,414,475 'product':1326,1327,1503 'product-organic-appl':1502 'product.formattedprice':1330 'product.instock':1339 'product.rating':1333 'productcel':1500 'productcell.buttons':1529 'productcell.exists':1507 'productcell.isenabled':1509 'productcell.label.isempty':1518 'productrow':1325 'programmat':1092 'proper':927 'properti':296,375,1490,1537 'provid':269,866,1036,1158,1834,1887 'quick':630 'rate':1332 'read':88,93,291,294,316,378,925,1348,1641 'receiv':1435 'red/green':1710 'reduc':281,283,682,704,716,944,1196,1666,1805,1813 'reducemot':663,696,701 'reducetranspar':667,718 'redund':1634 'refer':184,185,1934 'references/a11y-patterns.md':324,325,608,609,645,646,907,908,1020,1021,1139,1140,1314,1315,1937,1938 'reflect':1011 'region':1014 'regular':679,748 'relat':937 'reli':800 'remov':1259 'replac':684 'requir':74 'respect':280,655,1807,1815,1822 'restor':1552,1605 'return':232,362,1577,1609,1774 'reveal':1839 'review':5,179,182,1731 'review-checklist':181 'ring':1121 'rotor':113,116,625,626,638,649 'row':1619,1624,1764 'run':1372 'say':893,1402 'scaledmetr':258,618,1800 'scan':920,945,948,1017,1447 'screen':578,592,599,643,846,1290,1296,1389,1429,1885 'screenchang':602,1293 'secondari':735 'section':1854 'see':323,607,644,906,1019,1138,1313 'sendabl':1863 'sequenti':923 'set':424,777,795,1228,1240,1247,1266,1384,1398,1420,1442,1468,1514,1565,1639,1643,1852 'settingssheet':432 'sheet':227,353,429,1569,1607,1771 'shortcut':1108,1145,1930 'shorter':867 'show':894,897,1403,1406 'showcontent.toggle':699 'showsheet':411,425,431 'similar':1689 'simpler':1204 'simplifi':1160 'simplifiedcontentview':1191 'simul':1376 'singl':391 'single-target':390 'size':1466,1472,1677,1680 'skill':68 'skill-ios-accessibility' 'slide':703 'slight':434 'small':1693 'sole':1708 'solid':711,1816 'source-dpearson2699' 'space/enter':1041 'speak':865 'speakabl':828,913,1871 'specif':584,633,1521 'spoken':806 'spring':698 'standard':672,1004,1047 'state':408 'statictext':1305 'status':564,1280 'stock':1341,1344 'stop':946,1628 'stronger':725,1823 'struct':405,471 'style':1691 'submit':501 'submitbutton':470,506 'support':28,254,1082,1169,1799 'swift':404,461,538,561,659,694,710,751,1172,1298,1324,1491,1553 'swiftui':13,43,95,99,320,328,1048 'swiftui-accessibility-modifi':98 'swipe':972,1391,1627,1837,1901 'swipe-to-delet':971,1900 'swipe-to-rev':1836 'switch':22,56,134,137,916,918,964,966,992,1437,1444,1913 'switch-control':136 'symbol':837 'symbol-on':836 'system':117,121,256,275,651,739,1073,1106,1117,1679,1801,1928 'system-accessibility-prefer':120 'system-defin':1105 'systembackground':720,722 'systemimag':778 'systemnam':792 'tab':1054,1114,1426 'tab/shift-tab':1037 'tap':241,621,807,1202,1694,1790 'tappabl':1013 'target':242,392,402,457,622,808,819,905,949,1203,1286,1413,1695,1791 'targetview':590 'task':444 'task.sleep':449 'technolog':66,225 'test':169,172,888,1222,1353,1356,1381,1395,1417,1439,1462,1476,1486,1549,1584 'testing-access':171 'testproductrowaccess':1493 'testsheetdismissreturnsfocus':1555 'text':200,270,286,486,494,709,741,771,1255,1465,1471,1474,1621,1690,1714 'textfield':484,492 'throw':1494,1556 'titl':1548 'tool':1362 'topic-accessibility' 'topic-agent-skills' 'topic-ai-coding' 'topic-apple' 'topic-claude-code' 'topic-codex-skills' 'topic-cursor-skills' 'topic-ios' 'topic-ios-development' 'topic-liquid-glass' 'topic-localization' 'topic-mapkit' 'track':1090 'trait':36,211,306,333,527,1261,1300,1368,1591,1598,1635,1751,1785,1851 'transient':1279 'transit':438,593,1297 'transpar':284,705,714,1814 'trap':529,1274 'tri':447 'trigger':237,367,1579,1614,1778 'triggerbutton':1562 'triggerbutton.hasfocus':1586 'triggerbutton.tap':1566 'true':426,454,767,1242,1268,1309,1762 'type':108,111,251,606,612,635,1461,1648,1684,1798,1858 'ui':1485 'uiaccessibility.post':571,586,600 'uikit':15,45,155,159,547,559,1232,1238,1299,1317 'uikit-accessibility-pattern':158 'ungroup':1617 'uniqu':842,1873 'unspeak':815 'updat':579,1291 'upload':569,575 'usabl':53,935 'use':16,879,1061,1087,1100,1123,1206,1256,1479,1599,1629,1685,1749,1917 'user':48,629,850,968,1163,1736 'user-fac':47,1735 'v':1112 'valid':502,508 'valu':35,305,311,658,1543 'var':410,415,418,476,479,662,666,670,677,1183,1185 'variant':1077 'verif':1540 'verifi':900,1409,1431,1446,1488,1510,1519,1575,1739 'via':212,1752 'view':50,407,421,473,482,523,1068,1081,1130,1188,1239,1246,1272,1287,1364,1738,1916 'visibl':199,845,1254 'visual':764,1197 'visual-divid':763 'voic':20,58,129,132,796,798,816,873,890,1393,1400,1875 'voice-control':131 'voiceov':19,55,87,92,233,290,293,359,514,530,628,756,959,1380,1386,1610,1729 'weight':737 'whether':1079 'withanim':695 'within':843 'without':1253,1608,1697,1713,1725 'work':30,386,1236 'wrapper':376 'write':380,1484 'xcode':1359 'xctassertfals':1517 'xctasserttru':1506,1508,1531,1533,1585 'xctest':1478 'xcuiapplic':1497,1559 'xcuielement':1480 'xcuielementattribut':1536","prices":[{"id":"d5a086da-a653-4902-88c4-b8e4cd3a6598","listingId":"d2032bde-41e7-4ff2-ade0-0cb33cc9977a","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"dpearson2699","category":"swift-ios-skills","install_from":"skills.sh"},"createdAt":"2026-04-18T20:32:43.098Z"}],"sources":[{"listingId":"d2032bde-41e7-4ff2-ade0-0cb33cc9977a","source":"github","sourceId":"dpearson2699/swift-ios-skills/ios-accessibility","sourceUrl":"https://github.com/dpearson2699/swift-ios-skills/tree/main/skills/ios-accessibility","isPrimary":false,"firstSeenAt":"2026-04-18T22:01:02.412Z","lastSeenAt":"2026-04-22T06:53:43.731Z"},{"listingId":"d2032bde-41e7-4ff2-ade0-0cb33cc9977a","source":"skills_sh","sourceId":"dpearson2699/swift-ios-skills/ios-accessibility","sourceUrl":"https://skills.sh/dpearson2699/swift-ios-skills/ios-accessibility","isPrimary":true,"firstSeenAt":"2026-04-18T20:32:43.098Z","lastSeenAt":"2026-04-22T06:40:31.215Z"}],"details":{"listingId":"d2032bde-41e7-4ff2-ade0-0cb33cc9977a","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"dpearson2699","slug":"ios-accessibility","github":{"repo":"dpearson2699/swift-ios-skills","stars":468,"topics":["accessibility","agent-skills","ai-coding","apple","claude-code","codex-skills","cursor-skills","ios","ios-development","liquid-glass","localization","mapkit","networking","storekit","swift","swift-concurrency","swiftdata","swiftui","widgetkit","xcode"],"license":"other","html_url":"https://github.com/dpearson2699/swift-ios-skills","pushed_at":"2026-04-21T19:26:16Z","description":"Agent Skills for iOS 26+, Swift 6.3, SwiftUI, and modern Apple frameworks","skill_md_sha":"fed5c766cedf952c18af7b19a20c3a4d3adf1232","skill_md_path":"skills/ios-accessibility/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/dpearson2699/swift-ios-skills/tree/main/skills/ios-accessibility"},"layout":"multi","source":"github","category":"swift-ios-skills","frontmatter":{"name":"ios-accessibility","description":"Implement, review, or improve accessibility in iOS/macOS apps with SwiftUI and UIKit. Use when adding VoiceOver, Voice Control, Switch Control, or Full Keyboard Access support; when working with accessibility labels, hints, values, traits, or accessibilityInputLabels; when grouping or reordering accessibility elements; when managing focus with @AccessibilityFocusState or .focusable(); when supporting Dynamic Type with @ScaledMetric; when building custom rotors or accessibility actions; when writing automated accessibility tests with XCTest; when auditing a11y compliance; or when adapting UI for assistive technologies and system accessibility preferences."},"skills_sh_url":"https://skills.sh/dpearson2699/swift-ios-skills/ios-accessibility"},"updatedAt":"2026-04-22T06:53:43.731Z"}}