android-accessibility
Skill2 starsChanged 40 days agoMITView on GitHub
Use when building or reviewing Android UI for accessibility. Covers TalkBack, content descriptions, touch targets, Compose semantics, focus order, and Accessibility Scanner testing.
1 other project uses a version of this.
Adopted by
Most recently taken up by
- maxrave-dev/SimpMusictheir own version, first seen Oct 8, 2026
Other versions1 project uses a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 1
- maxrave-dev/SimpMusic★ 13ksame name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository31 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- android-architectureSkill
- android-background-workSkill
- android-data-persistenceSkill
- android-device-testingSkill
- android-e2e-verificationSkill
- android-ui-engineeringSkill
- api-and-interface-designSkill
- ci-cd-and-automationSkill
- code-review-and-qualitySkill
- code-simplificationSkill
- constraint-driven-developmentSkill
- context-engineeringSkill
- debugging-and-error-recoverySkill
- deprecation-and-migrationSkill
- documentation-and-adrsSkill
- doubt-driven-developmentSkill
- git-workflow-and-versioningSkill
- idea-refineSkill
- incremental-implementationSkill
- interview-meSkill
- observability-and-instrumentationSkill
- performance-optimizationSkill
- planning-and-task-breakdownSkill
- security-and-hardeningSkill
- shipping-and-launchSkill
- source-driven-developmentSkill
- spec-driven-developmentSkill
- test-driven-developmentSkill
- using-agent-skillsSkill
The file
We split this skill into the rules it gives an agent
8 rules. About 0 are common, 6 are distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈6
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 20
Before shipping any user-facing feature
- Very specific: line 75
Use null for purely decorative elements
- Distinctive: line 260
Verify announcements make sense without seeing the screen
- Distinctive: line 261
Check that all interactive elements are reachable
- Distinctive: line 262
Verify no elements are skipped or read in wrong order
- Distinctive: line 266
Run on every screen before shipping
- Very specific: line 285
Use android layout --diff after an interaction to inspect only what changed — keeps assertions tight when verifying live regions, error …
- Distinctive: line 334
No TalkBack or Accessibility Scanner testing before release
≈ “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.
Files
Android Accessibility
Overview
Accessibility is not optional — it's a requirement for reaching all users. This skill covers building accessible Android UIs with Jetpack Compose semantics, proper content descriptions, touch target sizing, TalkBack compatibility, and systematic testing with Accessibility Scanner.
When to Use
- Building new UI screens or components
- Reviewing existing UI for accessibility compliance
- Fixing accessibility issues flagged by Accessibility Scanner or users
- Before shipping any user-facing feature
Skip when: Working on non-UI code (repositories, use cases, networking).
Core Standards
| Requirement | Standard |
| Touch targets | Minimum 48dp x 48dp |
| Color contrast (text) | >= 4.5:1 (normal), >= 3:1 (large 18sp+) |
| Color contrast (UI components) | >= 3:1 against adjacent colors |
| Content descriptions | All meaningful visual elements |
| Focus order | Logical reading order |
| No color-only information | Additional indicators required |
Core Process
Step 1: Content Descriptions
- Every meaningful visual element needs a description:
// Icons that convey information
Icon(
imageVector = Icons.Default.Delete,
contentDescription = "Delete task", // Descriptive, not "delete icon"
)
// Decorative elements — explicitly null
Icon(
imageVector = Icons.Default.Circle,
contentDescription = null, // Decorative, TalkBack skips it
)
// Images
Image(
painter = painterResource(R.drawable.user_avatar),
contentDescription = "Profile photo of ${user.name}",
)
// IconButtons — the button gets the description
IconButton(
onClick = onDelete,
) {
Icon(
imageVector = Icons.Default.Delete,
contentDescription = "Delete task", // On the Icon, read by TalkBack
)
}- Description rules:
- Describe the action or meaning, not the visual appearance
- "Delete task" not "red trash can icon"
- "Search" not "magnifying glass"
- Use
nullfor purely decorative elements - Include dynamic content: "Profile photo of John" not just "profile photo"
Step 2: Touch Targets
- Enforce minimum 48dp touch targets:
// Compose handles this automatically for clickable elements,
// but verify small elements:
IconButton(
onClick = onToggle,
modifier = Modifier.size(48.dp), // At least 48dp
) {
Icon(
imageVector = Icons.Default.Check,
contentDescription = "Mark complete",
modifier = Modifier.size(24.dp), // Icon can be smaller
)
}
// For custom clickable elements, ensure minimum touch area:
@Composable
fun SmallChip(
label: String,
onClick: () -> Unit,
modifier: Modifier = Modifier,
) {
Surface(
onClick = onClick,
modifier = modifier.defaultMinSize(minHeight = 48.dp, minWidth = 48.dp),
) {
Text(label, modifier = Modifier.padding(horizontal = 12.dp, vertical = 4.dp))
}
}Step 3: Compose Semantics
- Use semantics for rich accessibility information:
// Merge child semantics for a single TalkBack announcement
@Composable
fun TaskItem(
task: Task,
onToggle: () -> Unit,
modifier: Modifier = Modifier,
) {
Row(
modifier = modifier
.semantics(mergeDescendants = true) {
// Custom state description
stateDescription = if (task.completed) "Completed" else "Not completed"
// Custom action
customActions = listOf(
CustomAccessibilityAction("Toggle completion") {
onToggle()
true
}
)
}
.clickable(onClick = onToggle),
) {
Checkbox(checked = task.completed, onCheckedChange = null)
Text(task.title)
}
}
// Headings for navigation
Text(
text = "My Tasks",
style = MaterialTheme.typography.headlineMedium,
modifier = Modifier.semantics { heading() },
)
// Live regions for dynamic content
Text(
text = "3 items remaining",
modifier = Modifier.semantics { liveRegion = LiveRegionMode.Polite },
)- Semantics rules:
mergeDescendants = truefor compound components (card with title + subtitle)heading()for section titles (enables TalkBack heading navigation)liveRegionfor content that updates dynamically (counters, status)stateDescriptionfor custom state (not just "checked/unchecked")Rolefor custom interactive elements
Step 4: Focus Order
- Ensure logical focus order:
// Default: top-to-bottom, start-to-end (matches visual order)
// Override when visual order differs from reading order:
@Composable
fun HeaderWithAction(
title: String,
onAction: () -> Unit,
) {
Row {
// TalkBack reads title first, then action button
Text(
text = title,
modifier = Modifier
.weight(1f)
.semantics { heading() },
)
IconButton(onClick = onAction) {
Icon(Icons.Default.Settings, contentDescription = "Settings")
}
}
}
// Focus management for dialogs and sheets:
@Composable
fun TaskDialog(onDismiss: () -> Unit) {
val focusRequester = remember { FocusRequester() }
AlertDialog(
onDismissRequest = onDismiss,
title = {
Text(
"Delete Task?",
modifier = Modifier.focusRequester(focusRequester),
)
},
// Request focus when dialog appears
confirmButton = { /* ... */ },
)
LaunchedEffect(Unit) {
focusRequester.requestFocus()
}
}Step 5: Color and Contrast
- Don't rely on color alone:
// BAD: only color distinguishes status
Text(
text = task.title,
color = if (task.overdue) Color.Red else Color.Black,
)
// GOOD: color + icon + text
Row {
if (task.overdue) {
Icon(
Icons.Default.Warning,
contentDescription = null, // Read as part of merged semantics
tint = MaterialTheme.colorScheme.error,
)
}
Text(
text = task.title,
color = if (task.overdue) MaterialTheme.colorScheme.error
else MaterialTheme.colorScheme.onSurface,
)
if (task.overdue) {
Text(
text = "Overdue",
color = MaterialTheme.colorScheme.error,
style = MaterialTheme.typography.labelSmall,
)
}
}- Use Material theme colors — they're designed for contrast compliance:
onSurfaceonsurface— guaranteed contrastonPrimaryonprimary— guaranteed contrasterrorandonError— guaranteed contrast
Step 6: Testing
- TalkBack testing (manual):
- Enable TalkBack: Settings → Accessibility → TalkBack
- Swipe right to move to next element
- Verify announcements make sense without seeing the screen
- Check that all interactive elements are reachable
- Verify no elements are skipped or read in wrong order
- Accessibility Scanner (automated):
- Install from Play Store: "Accessibility Scanner" by Google
- Run on every screen before shipping
- Fixes: touch target size, contrast ratio, content descriptions
android layoutfor scriptable accessibility assertions:android layout --prettyreturns JSON withcontent-desc,role, andboundsper node — turn it into automated scans you can run from a script or CI step.# Fail the build if any Button is missing content-desc android layout --pretty \ | jq -e '.nodes[] | select(.role=="Button" and ((.["content-desc"] // "") == ""))' \ && echo "FAIL: unlabeled button" && exit 1 # Flag touch targets smaller than 48dp (assuming density-converted bounds) android layout --pretty \ | jq '.nodes[] | select(.role=="Button") | {id: .["resource-id"], bounds}' \ | review_target_sizes.shUse
android layout --diffafter an interaction to inspect only what changed — keeps assertions tight when verifying live regions, error toasts, or focus shifts. Whenlayoutreturns nothing useful (WebView, animation), fall back toandroid screen capture --annotate -o screen.pngand visually verify focus order. See../../references/android-cli-reference.md.No device needed for composables:
android studio render-compose-preview --print-semantics <file> <composable>emits the accessibility semantics tree of a@Previewas JSON — assert oncontentDescription,role, and heading semantics straight from the preview, before anything is installed (requires a running Android Studio with Gemini; see../../references/android-cli-reference.md).- Compose UI tests for accessibility:
@Test
fun taskItem_hasContentDescription() {
composeTestRule.setContent {
TaskItem(task = Task("1", "Buy groceries", false), onToggle = {})
}
composeTestRule
.onNodeWithContentDescription("Buy groceries")
.assertExists()
}
@Test
fun deleteButton_hasMeaningfulDescription() {
composeTestRule.setContent {
TaskItem(task = sampleTask, onToggle = {}, onDelete = {})
}
composeTestRule
.onNodeWithContentDescription("Delete task")
.assertExists()
.assertHasClickAction()
}Common Rationalizations
| Shortcut | Why It Fails |
| "We'll add accessibility later" | Retrofitting is 5-10x harder than building accessible from the start. |
| "Our users don't use TalkBack" | 15% of the world's population has a disability. You don't know your users. |
| "ContentDescription is visual boilerplate" | It's the only way screen reader users interact with your app. |
| "Material components handle accessibility" | Material provides a foundation. You still need content descriptions, focus order, and semantic grouping. |
| "Touch targets look too big" | The visual element can be 24dp. The touch target must be 48dp. They're independent. |
Red Flags
- Images or icons without content descriptions
- Touch targets smaller than 48dp
- Color as the only differentiator
- Missing heading semantics on section titles
- No
mergeDescendantson compound components - Hardcoded colors that may not meet contrast ratios
- No TalkBack or Accessibility Scanner testing before release
contentDescription = ""(should benullfor decorative)
Verification
- All meaningful images/icons have descriptive
contentDescription - Decorative elements use
contentDescription = null - All touch targets >= 48dp x 48dp
- Color is never the only differentiator
- Section headings use
semantics { heading() } - Compound components use
mergeDescendants = true - Dynamic content uses
liveRegion - Focus order matches logical reading order
- TalkBack tested on all screens
- Accessibility Scanner reports zero critical issues
- Compose tests verify content descriptions exist
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
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.

