agentleFS
DesquaredDesquared/agents-rules-skills/skills/ios-accessibility-validator/SKILL.md

ios-accessibility-validator

Skill4 starsChanged 3 months agoMITView on GitHub

Checks and suggests accessibility improvements for SwiftUI and UIKit code including VoiceOver, Dynamic Type, color contrast, motion, and input methods. Use when creating or modifying UI components, views, or when the user asks about accessibility.

1 other project uses a version of this.

Adopted by

Most recently taken up by

The file

We split this skill into the rules it gives an agent

1 rule. About 0 are common, 0 are distinctive, and 1 is very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈0

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 1

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    When working with UIKit views or UIViewRepresentable wrappers, the same principles apply but through UIKit's accessibility API:

    line 83

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Accessibility Validator

Core Checklist (applies to most projects)

VoiceOver & Screen Reader

  • Interactive elements have .accessibilityLabel() or meaningful built-in label
  • Decorative / purely visual elements use .accessibilityHidden(true)
  • Related elements grouped with .accessibilityElement(children: .combine) or .accessibilityElement(children: .contain)
  • Complex controls provide .accessibilityHint() when label alone is insufficient
  • Appropriate .accessibilityTraits (.button, .header, .image, .adjustable, .toggle, etc.)
  • Stateful controls provide .accessibilityValue() (e.g., "50%", "3 of 10", "On")
  • Custom gestures have equivalent .accessibilityAction() alternatives
  • Labels & hints are localized (use LocalizedStringKey or NSLocalizedString)
  • Use .accessibilityRotor() to provide quick navigation for repeated content types (feeds, search results, settings)

Dynamic Type & Text Scaling

  • Use semantic font styles (.font(.body), .headline, .title, etc.) — avoid .system(size:)
  • Support at least 200% text scaling without truncation, overlap, or horizontal scrolling
  • Use @ScaledMetric or .dynamicTypeSize modifiers for padding, spacing, icon sizes
  • Layout adapts gracefully to largest Dynamic Type sizes (use .minimumScaleFactor sparingly)
  • Use ViewThatFits to provide alternative layouts at extreme Dynamic Type sizes (e.g., vertical instead of horizontal)

Color & Visual Indicators

  • Text contrast ≥ 4.5:1 (normal), ≥ 3:1 for large/bold text (≥18 pt bold or ≥24 pt regular)
  • Use semantic colors (.primary, .secondary, .accentColor, .fill) over hardcoded colors
  • Color is not the only way information is conveyed (use icons, patterns, text too)
  • Test with both light and dark appearance — ensure contrast holds in both
  • Support Increase Contrast setting (.accessibilityContrast environment value) with higher-contrast color variants

Touch & Interaction Targets

  • Minimum touch target 44×44 pt (or 48×48 recommended in dense UIs)
  • .contentShape(Rectangle()) used when hit area needs to be larger than visible bounds

Focus Management

  • Use @AccessibilityFocusState to programmatically move VoiceOver focus after async updates or navigation
  • Focus moves logically after alerts, sheets, or content changes
  • .accessibilityAddTraits(.isModal) on modal overlays to trap focus

Additional Checks (regulated, enterprise, or high-quality apps)

  • Reduced Motion: honor .environment(\.accessibilityReduceMotion) — replace motion with static alternatives
  • Differentiate Without Color: use shapes, patterns, underlines, icons when relying on color
  • Voice Control: test common spoken phrases work (custom .accessibilityIdentifier when needed)
  • Voice Control Input Labels: provide .accessibilityInputLabels() for elements where the visible label may be awkward to speak
  • Switch Control / Full Keyboard Access: testable via Accessibility Inspector
  • Accessibility Sort Priority & Activation Point when spatial order is non-obvious

Quick Fixes

IssueFixSeverity
Missing label.accessibilityLabel("Add to cart")🔴
Decorative image / icon.accessibilityHidden(true)🔴
Group of related elements.accessibilityElement(children: .combine)🔴
Contrast too lowUse .foregroundStyle(.primary) or semantic color set🔴
Custom gesture with no alternativeProvide .accessibilityAction() equivalent🔴
Small tap target.frame(minWidth: 44, minHeight: 44) or .contentShape()🟡
Fixed font sizeUse .body, .title2, etc.🟡
Motion / animation heavy.transaction { $0.disablesAnimations = true } when reduce motion🟡
Focus doesn't move after content change@AccessibilityFocusState to move focus programmatically🟡
No dark mode contrast checkTest both appearances, use semantic colors🟡
Using AnyView type erasureReplace with @ViewBuilder or concrete types — hurts accessibility tree diffing🟢
Missing .accessibilityInputLabels()Add alternative spoken phrases for Voice Control🟢

UIKit Bridging

When working with UIKit views or UIViewRepresentable wrappers, the same principles apply but through UIKit's accessibility API:

// UIView accessibility essentials
view.accessibilityLabel = "Add to cart"
view.accessibilityTraits = .button
view.accessibilityValue = "3 items"
view.isAccessibilityElement = true

// Focus management in UIKit
UIAccessibility.post(notification: .screenChanged, argument: targetView)
UIAccessibility.post(notification: .layoutChanged, argument: targetView)

// Grouping in UIKit
containerView.isAccessibilityElement = false
containerView.accessibilityElements = [label, button]

Testing & Debug Tools

Xcode & Simulator

  • Accessibility Inspector (Xcode → Open Developer Tool) — audit labels, traits, contrast, hit areas
  • VoiceOver on device — real-world screen reader testing (Settings → Accessibility → VoiceOver)
  • Voice Control — test spoken commands match labels (Settings → Accessibility → Voice Control)

In-Code Testing

// Dynamic Type preview in Xcode Previews
#Preview {
    MyView()
        .environment(\.sizeCategory, .accessibilityExtraExtraExtraLarge)
}
// Reduce motion preview
#Preview {
    MyView()
        .environment(\.accessibilityReduceMotion, true)
}
// Increase contrast preview
#Preview {
    MyView()
        .environment(\.accessibilityContrast, .increased)
}

Snapshot & Automated Testing

  • accessibilitySnapshot testing with SnapshotTesting library
  • XCTest accessibility audits: try app.performAccessibilityAudit() (Xcode 15+)

Severity Legend

🔴 Critical — Blocks screen reader users or fails basic WCAG 2.1/2.2 Level AA

🟡 Moderate — Reduces usability / fails enhanced criteria

🟢 Minor — Polish / future-proofs

Notes: Core checklist targets WCAG 2.1 AA + Apple Human Interface Guidelines. Additional checks help reach WCAG AAA or public-sector requirements.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.