Add accessibility
Skill yusufkaran/swiftui-autotest-skill/skills/add-accessibility
Scan SwiftUI views and add missing accessibility identifiers using a consistent {screen}-{type}-{name} naming convention. Also flags Dynamic Type compatibility issues. Use when you need to add accessibility support, make views testable, add VoiceOver labels, or prepare for UI testing.From its SKILL.md
npx -y skills add yusufkaran/swiftui-autotest-skill --skill add-accessibilityAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 24 stars24 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
5.6 KB, as published. Nobody here has run it
Add Accessibility Skill
Overview
Use this skill to scan all SwiftUI files in a project, find interactive elements missing accessibility identifiers, and add them using a consistent {screen}-{type}-{name} naming convention. Also flags Dynamic Type compatibility issues without auto-fixing them.
Options
--dry-run: Don't modify files, only report what would be changed--path=<path>: Scan only the specified directory (default: all SwiftUI files)--verbose: Log each identifier added in detail
Workflow
1) Scan & Analyze
-
Find all
*.swiftfiles in the project -
Filter to files containing SwiftUI views (
struct X: View,#Preview, etc.) -
In each file, detect these interactive elements:
Button— buttonsTextFieldandSecureField— input fieldsImage— imagesToggle— toggle switchesSlider— slidersPicker— pickersDatePicker— date pickersNavigationLink— navigation linksTabViewtab items.onTapGestureviews — tap gesture elementsLink— external links
-
For each element, check existing accessibility state:
- Has
.accessibilityIdentifier()? → SKIP - Has
.accessibilityLabel()? → SKIP - If either exists, do not touch it
- Has
2) Generate Identifiers
Naming convention: {screen}-{type}-{name}
Screen name: derived from the filename
LoginView.swift→loginOnboardingStepView.swift→onboarding-stepHomeTabView.swift→home-tab- Remove
Viewsuffix, convert camelCase to kebab-case
Type: based on the element type
| SwiftUI Element | Type |
|---|---|
| Button | button |
| TextField | textfield |
| SecureField | securefield |
| Image | image |
| Toggle | toggle |
| Slider | slider |
| Picker | picker |
| DatePicker | datepicker |
| NavigationLink | navlink |
| Link | link |
| .onTapGesture view | tap |
| TabView item | tab |
Name: derived from the element's content
Button("Continue")→continueTextField("Email", ...)→emailImage(systemName: "gear")→gearImage("hero-banner")→hero-bannerToggle("Notifications", ...)→notifications- No content or too complex → number sequentially (
button-1,button-2)
Example results:
login-button-continue
login-textfield-email
login-securefield-password
onboarding-image-hero-banner
settings-toggle-notifications
home-tab-profile
3) Apply Changes
Add .accessibilityIdentifier("generated-id") to each element missing one:
// BEFORE
Button("Continue") {
viewModel.proceed()
}
// AFTER
Button("Continue") {
viewModel.proceed()
}
.accessibilityIdentifier("login-button-continue")
For Images, also add accessibilityLabel (for VoiceOver):
// BEFORE
Image(systemName: "gear")
// AFTER
Image(systemName: "gear")
.accessibilityIdentifier("settings-image-gear")
.accessibilityLabel("Settings")
For onTapGesture views, mark as accessibility elements:
// BEFORE
HStack {
Image("avatar")
Text(user.name)
}
.onTapGesture { showProfile() }
// AFTER
HStack {
Image("avatar")
Text(user.name)
}
.onTapGesture { showProfile() }
.accessibilityElement(children: .combine)
.accessibilityIdentifier("profile-tap-user-row")
.accessibilityAddTraits(.isButton)
4) Dynamic Type Check
Check Text elements for Dynamic Type compatibility:
-
Flag (report as warnings, do NOT auto-fix):
Textwithout.lineLimit()when the content could be longTextwithout.minimumScaleFactor()in constrained areas.font(.system(size: XX))with hardcoded font sizes instead of dynamic fonts like.font(.title),.font(.body)
-
Report format:
⚠️ Dynamic Type Warnings:
LoginView.swift:42 - Text("Welcome back...") → missing lineLimit or minimumScaleFactor
LoginView.swift:58 - Text(...).font(.system(size: 14)) → consider using dynamic font (.body, .caption, etc.)
SettingsView.swift:23 - Text(longString) → missing lineLimit, risk of overflow with large text
5) Summary Report
Show a summary when the scan is complete:
✅ Accessibility Scan Complete
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Files scanned: 24
Elements found: 87
Already present: 31 (skipped)
Newly added: 56
- Button: 18
- TextField: 8
- Image: 12
- Toggle: 6
- Other: 12
⚠️ Dynamic Type Warnings: 7
(details above)
Pattern: {screen}-{type}-{name}
Important Rules
- NEVER modify or remove existing accessibility modifiers
- NEVER change the view's functionality or appearance
- Only add
.accessibilityIdentifier(),.accessibilityLabel(),.accessibilityElement(),.accessibilityAddTraits() - Do NOT wrap in
#if DEBUG— identifiers must be in production too (for real accessibility / VoiceOver) - If unsure about a name, use
{screen}-{type}-{index}format and flag it in verbose mode - Dynamic Type warnings are REPORT ONLY — do not auto-fix, leave it to the user
- In
--dry-runmode, do not modify any files — only show the plan - After modifying each file, run a compile check — if a syntax error is introduced, revert