{"id":"6807a6a0-8f1e-4ff2-a2fe-294bf34e2e0c","shortId":"MC5QE2","kind":"skill","title":"accessibility","tagline":"27 Android skills for AI agents (Claude Code, Codex, Cursor). Fixes Supabase auth, Hilt errors, design inconsistency, kapt→ksp, missing UiState states. Reduced my token bills 5×. FitGenZ AI shipped in 18 days.","description":"# Android Accessibility\r\n\r\nAccessibility is not optional — it's required by law in many markets and checked by the Play Store.\r\n\r\n## Rule 1: Content descriptions for all interactive elements\r\n\r\n```kotlin\r\n// ✅ Every non-text interactive element needs contentDescription\r\nIconButton(onClick = onLike) {\r\n    Icon(\r\n        imageVector = if (isLiked) Icons.Filled.Favorite else Icons.Outlined.FavoriteBorder,\r\n        contentDescription = if (isLiked) \"Remove from favorites\" else \"Add to favorites\"\r\n        // Describe the ACTION, not the icon name\r\n    )\r\n}\r\n\r\n// ✅ Image with context\r\nAsyncImage(\r\n    model = imageUrl,\r\n    contentDescription = \"$productName product image\"  // meaningful description\r\n)\r\n\r\n// ✅ Decorative images — explicitly null\r\nIcon(Icons.Default.Star, contentDescription = null)  // decorative, screen reader skips it\r\n\r\n// ❌ Generic description\r\nIcon(Icons.Default.Favorite, contentDescription = \"icon\")  // useless to screen reader\r\n```\r\n\r\n## Rule 2: Minimum touch target — 48×48dp\r\n\r\n```kotlin\r\n// ✅ Ensure minimum touch target size\r\n@Composable\r\nfun SmallIconButton(onClick: () -> Unit, icon: ImageVector, contentDescription: String) {\r\n    Box(\r\n        modifier = Modifier\r\n            .size(48.dp)                     // minimum touch target\r\n            .clickable(\r\n                onClick = onClick,\r\n                interactionSource = remember { MutableInteractionSource() },\r\n                indication = rememberRipple(bounded = false)\r\n            ),\r\n        contentAlignment = Alignment.Center\r\n    ) {\r\n        Icon(\r\n            imageVector = icon,\r\n            contentDescription = contentDescription,\r\n            modifier = Modifier.size(24.dp)  // visual size separate from touch target\r\n        )\r\n    }\r\n}\r\n\r\n// ✅ Or use minimumInteractiveComponentSize modifier\r\nIcon(\r\n    imageVector = icon,\r\n    contentDescription = description,\r\n    modifier = Modifier.minimumInteractiveComponentSize()  // auto 48dp touch target\r\n)\r\n```\r\n\r\n## Rule 3: Semantic properties for complex components\r\n\r\n```kotlin\r\n// ✅ Card — merge all content for TalkBack\r\n@Composable\r\nfun ProductCard(product: Product, onAddToCart: () -> Unit) {\r\n    Card(\r\n        modifier = Modifier.semantics(mergeDescendants = true) {}\r\n        // TalkBack reads all child text as one item: \"Blue T-Shirt, $29.99, In stock\"\r\n    ) {\r\n        Column {\r\n            Text(product.name)\r\n            Text(\"$${product.price}\")\r\n            Text(if (product.inStock) \"In stock\" else \"Out of stock\")\r\n            Button(onClick = onAddToCart) { Text(\"Add to cart\") }\r\n        }\r\n    }\r\n}\r\n\r\n// ✅ Custom state description\r\nSwitch(\r\n    checked = isEnabled,\r\n    onCheckedChange = onToggle,\r\n    modifier = Modifier.semantics {\r\n        stateDescription = if (isEnabled) \"Notifications on\" else \"Notifications off\"\r\n    }\r\n)\r\n\r\n// ✅ Mark as heading for navigation\r\nText(\r\n    text = \"Today's Orders\",\r\n    style = MaterialTheme.typography.titleLarge,\r\n    modifier = Modifier.semantics { heading() }\r\n)\r\n\r\n// ✅ Custom action — add actions TalkBack can trigger\r\nLazyColumn {\r\n    items(items) { item ->\r\n        SwipeableItemCard(\r\n            item = item,\r\n            modifier = Modifier.semantics {\r\n                customActions = listOf(\r\n                    CustomAccessibilityAction(\"Delete ${item.title}\") {\r\n                        onDelete(item.id)\r\n                        true\r\n                    },\r\n                    CustomAccessibilityAction(\"Archive ${item.title}\") {\r\n                        onArchive(item.id)\r\n                        true\r\n                    }\r\n                )\r\n            }\r\n        )\r\n    }\r\n}\r\n```\r\n\r\n## Rule 4: Color contrast — WCAG AA minimum\r\n\r\n```kotlin\r\n// ✅ Use Material 3 color roles — contrast is guaranteed by the spec\r\nText(\r\n    text = \"Important message\",\r\n    color = MaterialTheme.colorScheme.onSurface   // guaranteed contrast on Surface\r\n)\r\n\r\n// ✅ Check custom colors with contrast tool\r\n// onSurface on Surface: contrast ratio ≥ 4.5:1 (WCAG AA)\r\n// onPrimary on Primary: contrast ratio ≥ 4.5:1\r\n\r\n// ❌ Custom colors without contrast check\r\nText(text = \"Label\", color = Color(0xFF888888))   // gray on white = likely fails WCAG\r\n```\r\n\r\n## Rule 5: Screen reader traversal order\r\n\r\n```kotlin\r\n// ✅ Control traversal order for complex layouts\r\n@Composable\r\nfun ProductHeader(name: String, price: String, rating: Float) {\r\n    Row(modifier = Modifier.semantics { isTraversalGroup = true }) {\r\n        Column(modifier = Modifier.weight(1f)) {\r\n            Text(name, modifier = Modifier.semantics { traversalIndex = 0f })\r\n            Text(price, modifier = Modifier.semantics { traversalIndex = 1f })\r\n        }\r\n        RatingBar(rating, modifier = Modifier.semantics { traversalIndex = 2f })\r\n    }\r\n}\r\n```\r\n\r\n## Rule 6: Live regions for dynamic content\r\n\r\n```kotlin\r\n// ✅ Announce changes to screen reader users\r\nText(\r\n    text = \"Found ${results.size} results\",\r\n    modifier = Modifier.semantics {\r\n        liveRegion = LiveRegionMode.Polite  // announced when content changes, doesn't interrupt\r\n    }\r\n)\r\n\r\n// LiveRegionMode.Assertive — interrupts current speech (use sparingly)\r\nText(\r\n    text = errorMessage,\r\n    modifier = Modifier.semantics {\r\n        liveRegion = LiveRegionMode.Assertive  // for critical errors only\r\n    }\r\n)\r\n```\r\n\r\n## Accessibility checklist (run before every release)\r\n\r\n- [ ] All interactive elements have meaningful `contentDescription`\r\n- [ ] All touch targets are ≥ 48×48dp\r\n- [ ] Cards and list items use `mergeDescendants = true`\r\n- [ ] Color-only information has a text/shape alternative\r\n- [ ] All text passes 4.5:1 contrast ratio (WCAG AA)\r\n- [ ] Headings marked with `heading()` semantic\r\n- [ ] Swipeable actions have `customActions` for TalkBack users\r\n- [ ] Dynamic content uses live regions\r\n- [ ] Tested with TalkBack enabled and touch exploration","tags":["accessibility","android","agent","skills","piyushverma0","agent-skills","ai-agent","antigravity","claude-code","codex","cursor","gemini-cli"],"capabilities":["skill","source-piyushverma0","skill-accessibility","topic-agent-skills","topic-ai-agent","topic-android","topic-antigravity","topic-claude-code","topic-codex","topic-cursor","topic-gemini-cli","topic-hilt","topic-jetpack-compose","topic-kotlin","topic-material3"],"categories":["android-agent-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/piyushverma0/android-agent-skills/accessibility","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add piyushverma0/android-agent-skills","source_repo":"https://github.com/piyushverma0/android-agent-skills","install_from":"skills.sh"}},"qualityScore":"0.454","qualityRationale":"deterministic score 0.45 from registry signals: · indexed on github topic:agent-skills · 8 github stars · SKILL.md body (5,854 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-05-18T19:09:08.441Z","embedding":null,"createdAt":"2026-05-18T13:14:47.782Z","updatedAt":"2026-05-18T19:09:08.441Z","lastSeenAt":"2026-05-18T19:09:08.441Z","tsv":"'0f':434 '0xff888888':391 '1':56,371,380,531 '18':33 '1f':428,440 '2':135 '24.dp':183 '27':2 '29.99':243 '2f':446 '3':206,340 '4':331 '4.5':370,379,530 '48':139,510 '48.dp':160 '48dp':140,202,511 '5':28,399 '6':448 'aa':335,373,535 'access':1,36,37,494 'action':94,301,303,542 'add':89,264,302 'agent':7 'ai':6,30 'alignment.center':175 'altern':526 'android':3,35 'announc':455,470 'archiv':325 'asyncimag':102 'auth':14 'auto':201 'bill':27 'blue':239 'bound':172 'box':156 'button':260 'card':213,226,512 'cart':266 'chang':456,473 'check':50,271,359,385 'checklist':495 'child':234 'claud':8 'clickabl':164 'code':9 'codex':10 'color':332,341,353,361,382,389,390,520 'color-on':519 'column':246,425 'complex':210,409 'compon':211 'compos':147,219,411 'content':57,216,453,472,549 'contentalign':174 'contentdescript':71,82,105,117,128,154,179,180,197,505 'context':101 'contrast':333,343,356,363,368,377,384,532 'control':405 'critic':491 'current':479 'cursor':11 'custom':267,300,360,381 'customaccessibilityact':318,324 'customact':316,544 'day':34 'decor':111,119 'delet':319 'describ':92 'descript':58,110,125,198,269 'design':17 'doesn':474 'dynam':452,548 'element':62,69,502 'els':80,88,256,282 'enabl':556 'ensur':142 'error':16,492 'errormessag':485 'everi':64,498 'explicit':113 'explor':559 'fail':396 'fals':173 'favorit':87,91 'fitgenz':29 'fix':12 'float':419 'found':463 'fun':148,220,412 'generic':124 'gray':392 'guarante':345,355 'head':287,299,536,539 'hilt':15 'icon':75,97,115,126,129,152,176,178,194,196 'iconbutton':72 'icons.default.favorite':127 'icons.default.star':116 'icons.filled.favorite':79 'icons.outlined.favoriteborder':81 'imag':99,108,112 'imageurl':104 'imagevector':76,153,177,195 'import':351 'inconsist':18 'indic':170 'inform':522 'interact':61,68,501 'interactionsourc':167 'interrupt':476,478 'isen':272,279 'islik':78,84 'istraversalgroup':423 'item':238,308,309,310,312,313,515 'item.id':322,328 'item.title':320,326 'kapt':19 'kotlin':63,141,212,337,404,454 'ksp':20 'label':388 'law':45 'layout':410 'lazycolumn':307 'like':395 'list':514 'listof':317 'live':449,551 'liveregion':468,488 'liveregionmode.assertive':477,489 'liveregionmode.polite':469 'mani':47 'mark':285,537 'market':48 'materi':339 'materialtheme.colorscheme.onsurface':354 'materialtheme.typography.titlelarge':296 'meaning':109,504 'merg':214 'mergedescend':229,517 'messag':352 'minimum':136,143,161,336 'minimuminteractivecomponents':192 'miss':21 'model':103 'modifi':157,158,181,193,199,227,275,297,314,421,426,431,437,443,466,486 'modifier.minimuminteractivecomponentsize':200 'modifier.semantics':228,276,298,315,422,432,438,444,467,487 'modifier.size':182 'modifier.weight':427 'mutableinteractionsourc':169 'name':98,414,430 'navig':289 'need':70 'non':66 'non-text':65 'notif':280,283 'null':114,118 'onaddtocart':224,262 'onarch':327 'oncheckedchang':273 'onclick':73,150,165,166,261 'ondelet':321 'one':237 'onlik':74 'onprimari':374 'onsurfac':365 'ontoggl':274 'option':40 'order':294,403,407 'pass':529 'play':53 'price':416,436 'primari':376 'product':107,222,223 'product.instock':253 'product.name':248 'product.price':250 'productcard':221 'producthead':413 'productnam':106 'properti':208 'rate':418,442 'ratingbar':441 'ratio':369,378,533 'read':232 'reader':121,133,401,459 'reduc':24 'region':450,552 'releas':499 'rememb':168 'rememberrippl':171 'remov':85 'requir':43 'result':465 'results.size':464 'role':342 'row':420 'rule':55,134,205,330,398,447 'run':496 'screen':120,132,400,458 'semant':207,540 'separ':186 'ship':31 'shirt':242 'size':146,159,185 'skill':4 'skill-accessibility' 'skip':122 'smalliconbutton':149 'source-piyushverma0' 'spare':482 'spec':348 'speech':480 'state':23,268 'statedescript':277 'stock':245,255,259 'store':54 'string':155,415,417 'style':295 'supabas':13 'surfac':358,367 'swipeabl':541 'swipeableitemcard':311 'switch':270 't-shirt':240 'talkback':218,231,304,546,555 'target':138,145,163,189,204,508 'test':553 'text':67,235,247,249,251,263,290,291,349,350,386,387,429,435,461,462,483,484,528 'text/shape':525 'today':292 'token':26 'tool':364 'topic-agent-skills' 'topic-ai-agent' 'topic-android' 'topic-antigravity' 'topic-claude-code' 'topic-codex' 'topic-cursor' 'topic-gemini-cli' 'topic-hilt' 'topic-jetpack-compose' 'topic-kotlin' 'topic-material3' 'touch':137,144,162,188,203,507,558 'travers':402,406 'traversalindex':433,439,445 'trigger':306 'true':230,323,329,424,518 'uistat':22 'unit':151,225 'use':191,338,481,516,550 'useless':130 'user':460,547 'visual':184 'wcag':334,372,397,534 'white':394 'without':383","prices":[{"id":"ec539839-1282-49ca-8428-c90396a36371","listingId":"6807a6a0-8f1e-4ff2-a2fe-294bf34e2e0c","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"piyushverma0","category":"android-agent-skills","install_from":"skills.sh"},"createdAt":"2026-05-18T13:14:47.782Z"}],"sources":[{"listingId":"6807a6a0-8f1e-4ff2-a2fe-294bf34e2e0c","source":"github","sourceId":"piyushverma0/android-agent-skills/accessibility","sourceUrl":"https://github.com/piyushverma0/android-agent-skills/tree/main/skills/accessibility","isPrimary":false,"firstSeenAt":"2026-05-18T13:14:47.782Z","lastSeenAt":"2026-05-18T19:09:08.441Z"}],"details":{"listingId":"6807a6a0-8f1e-4ff2-a2fe-294bf34e2e0c","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"piyushverma0","slug":"accessibility","github":{"repo":"piyushverma0/android-agent-skills","stars":8,"topics":["agent-skills","ai-agent","android","antigravity","claude-code","codex","cursor","gemini-cli","hilt","jetpack-compose","kotlin","material3","open-source","skills","supabase"],"license":"mit","html_url":"https://github.com/piyushverma0/android-agent-skills","pushed_at":"2026-04-27T09:15:31Z","description":"27 Android skills for AI agents (Claude Code, Codex, Cursor). Fixes Supabase auth, Hilt errors, design inconsistency, kapt→ksp, missing UiState states. Reduced my token bills 5×. FitGenZ AI shipped in 18 days.","skill_md_sha":"ba7fc85cc1a343f6fb9b5f2a257020fb54745d5d","skill_md_path":"skills/accessibility/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/piyushverma0/android-agent-skills/tree/main/skills/accessibility"},"layout":"multi","source":"github","category":"android-agent-skills","frontmatter":{},"skills_sh_url":"https://skills.sh/piyushverma0/android-agent-skills/accessibility"},"updatedAt":"2026-05-18T19:09:08.441Z"}}