Mobile accessibility testing skill for WCAG compliance, VoiceOver/TalkBack validation, dynamic type support, color contrast analysis, and accessibility auditing across iOS and Android platforms.
Audits mobile accessibility for WCAG compliance, screen reader support, dynamic type, and color contrast across iOS and Android.
npx claudepluginhub a5c-ai/babysitterThis skill is limited to using the following tools:
README.mdComprehensive mobile accessibility testing and validation for iOS and Android platforms, ensuring WCAG 2.1/2.2 compliance and optimal screen reader compatibility.
This skill provides capabilities for testing mobile application accessibility, including screen reader compatibility, dynamic type support, color contrast validation, and compliance with Web Content Accessibility Guidelines (WCAG) adapted for mobile platforms.
# Accessibility testing tools
xcode-select --install
# UI testing with accessibility focus
pod 'ViewInspector' # SwiftUI testing
// build.gradle
dependencies {
androidTestImplementation 'androidx.test.espresso:espresso-accessibility:3.5.1'
}
# Accessibility testing CLI tools
npm install -g @axe-core/cli
pip install accessibility-checker
import SwiftUI
struct AccessibleButton: View {
var body: some View {
Button(action: { /* action */ }) {
Image(systemName: "heart.fill")
}
.accessibilityLabel("Add to favorites")
.accessibilityHint("Double tap to add this item to your favorites list")
.accessibilityAddTraits(.isButton)
}
}
struct AccessibleList: View {
var body: some View {
List {
ForEach(items) { item in
ItemRow(item: item)
.accessibilityElement(children: .combine)
.accessibilityLabel("\(item.title), \(item.subtitle)")
.accessibilityValue(item.isSelected ? "Selected" : "Not selected")
}
}
.accessibilityIdentifier("items_list")
}
}
import UIKit
class AccessibleViewController: UIViewController {
func configureAccessibility() {
// Basic label
button.accessibilityLabel = "Submit order"
button.accessibilityHint = "Double tap to submit your order"
// Grouped elements
containerView.isAccessibilityElement = true
containerView.accessibilityLabel = "Order summary: 3 items, total $45.99"
// Custom actions
cell.accessibilityCustomActions = [
UIAccessibilityCustomAction(name: "Delete", target: self, selector: #selector(deleteItem)),
UIAccessibilityCustomAction(name: "Edit", target: self, selector: #selector(editItem))
]
}
}
import androidx.compose.ui.semantics.*
@Composable
fun AccessibleButton() {
IconButton(
onClick = { /* action */ },
modifier = Modifier.semantics {
contentDescription = "Add to favorites"
role = Role.Button
}
) {
Icon(Icons.Filled.Favorite, contentDescription = null)
}
}
@Composable
fun AccessibleCard(item: Item) {
Card(
modifier = Modifier.semantics(mergeDescendants = true) {
contentDescription = "${item.title}, ${item.subtitle}"
stateDescription = if (item.isSelected) "Selected" else "Not selected"
}
) {
// Card content
}
}
import android.view.View
import android.view.accessibility.AccessibilityNodeInfo
class AccessibleActivity : AppCompatActivity() {
fun configureAccessibility() {
// Basic content description
imageButton.contentDescription = "Add to favorites"
// Important for accessibility
decorativeImage.importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_NO
// Live regions for dynamic content
statusTextView.accessibilityLiveRegion = View.ACCESSIBILITY_LIVE_REGION_POLITE
// Custom accessibility delegate
customView.accessibilityDelegate = object : View.AccessibilityDelegate() {
override fun onInitializeAccessibilityNodeInfo(host: View, info: AccessibilityNodeInfo) {
super.onInitializeAccessibilityNodeInfo(host, info)
info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK)
info.contentDescription = "Custom description"
}
}
}
}
// iOS - Check contrast ratio
import UIKit
func calculateContrastRatio(foreground: UIColor, background: UIColor) -> Double {
let fgLuminance = relativeLuminance(foreground)
let bgLuminance = relativeLuminance(background)
let lighter = max(fgLuminance, bgLuminance)
let darker = min(fgLuminance, bgLuminance)
return (lighter + 0.05) / (darker + 0.05)
}
func relativeLuminance(_ color: UIColor) -> Double {
var r: CGFloat = 0, g: CGFloat = 0, b: CGFloat = 0
color.getRed(&r, green: &g, blue: &b, alpha: nil)
let transform: (CGFloat) -> Double = { value in
let v = Double(value)
return v <= 0.03928 ? v / 12.92 : pow((v + 0.055) / 1.055, 2.4)
}
return 0.2126 * transform(r) + 0.7152 * transform(g) + 0.0722 * transform(b)
}
// Usage
let ratio = calculateContrastRatio(foreground: .label, background: .systemBackground)
let meetsWCAGAA = ratio >= 4.5 // Normal text
let meetsWCAGAAA = ratio >= 7.0 // Enhanced
import XCTest
class AccessibilityTests: XCTestCase {
func testVoiceOverNavigation() {
let app = XCUIApplication()
app.launch()
// Verify accessibility elements exist
XCTAssertTrue(app.buttons["Submit order"].exists)
XCTAssertTrue(app.staticTexts["Order total"].exists)
// Check accessibility traits
let submitButton = app.buttons["Submit order"]
XCTAssertTrue(submitButton.isEnabled)
// Navigate with VoiceOver gestures (simulated)
let elements = app.descendants(matching: .any).allElementsBoundByAccessibilityElement
XCTAssertGreaterThan(elements.count, 0)
}
func testDynamicTypeSupport() {
let app = XCUIApplication()
app.launchArguments = ["-UIPreferredContentSizeCategoryName", "UICTContentSizeCategoryAccessibilityXXL"]
app.launch()
// Verify layout doesn't break at large text sizes
XCTAssertTrue(app.staticTexts["Title"].exists)
XCTAssertFalse(app.staticTexts["Title"].frame.isEmpty)
}
}
import androidx.test.espresso.accessibility.AccessibilityChecks
import org.junit.BeforeClass
class AccessibilityTest {
companion object {
@BeforeClass
@JvmStatic
fun enableAccessibilityChecks() {
AccessibilityChecks.enable()
.setRunChecksFromRootView(true)
}
}
@Test
fun testScreenAccessibility() {
onView(withId(R.id.main_layout))
.check(matches(isDisplayed()))
// Automatic accessibility checks run on every view interaction
onView(withId(R.id.submit_button))
.perform(click())
}
}
const accessibilityTestTask = defineTask({
name: 'accessibility-testing',
description: 'Test mobile app accessibility compliance',
inputs: {
platform: { type: 'string', required: true, enum: ['ios', 'android', 'both'] },
wcagLevel: { type: 'string', required: true, enum: ['A', 'AA', 'AAA'] },
projectPath: { type: 'string', required: true },
testScreens: { type: 'array', items: { type: 'string' } }
},
outputs: {
complianceReport: { type: 'object' },
violations: { type: 'array' },
recommendations: { type: 'array' },
score: { type: 'number' }
},
async run(inputs, taskCtx) {
return {
kind: 'skill',
title: `Test ${inputs.wcagLevel} accessibility for ${inputs.platform}`,
skill: {
name: 'accessibility-testing',
context: {
operation: 'audit',
platform: inputs.platform,
wcagLevel: inputs.wcagLevel,
projectPath: inputs.projectPath,
screens: inputs.testScreens
}
},
io: {
inputJsonPath: `tasks/${taskCtx.effectId}/input.json`,
outputJsonPath: `tasks/${taskCtx.effectId}/result.json`
}
};
}
});
{
"mcpServers": {
"axiom": {
"command": "npx",
"args": ["axiom-mcp"],
"env": {
"XCODE_PROJECT": "/path/to/project.xcodeproj"
}
}
}
}
a11y_audit_ios - Run iOS Accessibility Inspector audita11y_audit_android - Run Android Accessibility Scannercheck_contrast_ratio - Validate color contrastvalidate_touch_targets - Check touch target sizestest_screen_reader - Simulate screen reader navigationgenerate_a11y_report - Create compliance reportActivates when the user asks about AI prompts, needs prompt templates, wants to search for prompts, or mentions prompts.chat. Use for discovering, retrieving, and improving prompts.
Search, retrieve, and install Agent Skills from the prompts.chat registry using MCP tools. Use when the user asks to find skills, browse skill catalogs, install a skill for Claude, or extend Claude's capabilities with reusable AI agent components.
This skill should be used when the user wants to "create a skill", "add a skill to plugin", "write a new skill", "improve skill description", "organize skill content", or needs guidance on skill structure, progressive disclosure, or skill development best practices for Claude Code plugins.