flutter-accessibility
Skill12 starsChanged 55 days agoMITView on GitHub
Use when implementing or auditing accessibility on a Flutter screen — the Semantics widget, screen-reader labels (TalkBack/VoiceOver), colour contrast, minimum tap-target size, system font scaling, or semantics in a web build. Also triggers on "make this accessible", "a11y", or a request for an accessibility review.
2 other projects use a version of this.
Adopted by
Most recently taken up by
- thienqo/flutter-skillstheir own version, first seen Nov 1, 2026
- thiennc-tesoglobal/flutter-skillstheir own version, first seen Aug 30, 2026
Other versions2 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 2
- thiennc-tesoglobal/flutter-skills★ 16same name
- thienqo/flutter-skills★ 16same 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 repository15 other files it gives its agents.
- flutter-cachingSkill
- flutter-clean-archSkill
- flutter-concurrencySkill
- flutter-dart-styleSkill
- flutter-design-systemSkill
- flutter-diSkill
- flutter-formsSkill
- flutter-monorepoSkill
- flutter-new-moduleSkill
- flutter-runSkill
- flutter-stateSkill
- flutter-store-cdSkill
- flutter-testingSkill
- flutter-themingSkill
- flutter-webSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
17 rules. About 0 are common, 8 are distinctive, and 9 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈8
Distinctive · estimate
This author's own choices. Worth a look.
9
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 24
If no mode specified, default to implement
- Distinctive: line 73
Follow WCAG 2.1 minimum contrast ratios:
- Distinctive: line 83
Use the Accessibility Scanner on Android (Settings > Accessibility)
- Distinctive: line 84
Run Lighthouse audit in Chrome DevTools for the web build
- Very specific: line 85
Use online contrast checkers (WebAIM Contrast Checker) with hex values from ds_colors.dart
- Very specific: line 93
When fixing, update colors in design_system/ tokens so the fix propagates everywhere.
- Distinctive: line 99
All interactive elements must be at least 48x48 logical pixels:
- Very specific: line 216
Ensure the HTML <title> tag is descriptive (e.g., "Product Catalog — Acme")
- Very specific: line 217
Add lang="pt-BR" to the <html> tag in index.html
- Very specific: line 242
Use minHeight / minWidth instead of fixed height / width for containers holding text
- Distinctive: line 243
Test with system font scale at 2.0x (Settings > Display > Font size)
- Very specific: line 244
Ensure text does not overflow or get clipped — use Flexible, Expanded, or overflow: TextOverflow.ellipsis with maxLines
- Distinctive: line 249
Only limit scale factor for truly constrained UI (e.g., small price badges):
- Very specific: line 302
Ensure all modals trap focus (Material showDialog and showModalBottomSheet do this automatically).
- Distinctive: line 308
Every meaningful image needs descriptive text:
- Very specific: line 362
Always use labelText on InputDecoration, not just hintText (hints disappear on focus)
- Distinctive: line 364
After form submission with errors, move focus to the first field with an error
≈ “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
You are implementing or auditing accessibility (a11y) for a Flutter app.
Context
Accessibility pressure differs by surface, and it changes what you prioritise:
- Customer-facing web — the highest bar. Screen-reader semantics are off by default on Flutter web (see section 5), the audience is unknown, and in many jurisdictions this is a legal requirement, not a nicety.
- Internal/admin web — keyboard navigation and contrast matter most; staff use these all day.
- Mobile — platform screen readers (TalkBack/VoiceOver) mostly work if you give widgets labels and keep tap targets large enough.
Choose based on the skill argument, if one was given, or on the screen/task at hand:
audit— Review existing code for a11y violations and produce a report with fixesimplement— Add accessibility annotations and fixes to existing widgetsweb-setup— Enable Flutter web semantics and configure for screen readers- If no mode specified, default to
implement
1. Semantic Annotations
Wrap custom widgets with Semantics to expose meaning to assistive technology:
// Label interactive elements
Semantics(
label: 'Adicionar ao pedido',
button: true,
child: CustomAddButton(...),
)
// Group related elements into a single announcement
MergeSemantics(
child: Row(
children: [
Icon(Icons.star),
Text('4.5'),
],
),
)
// Hide decorative elements from screen readers
ExcludeSemantics(
child: DecorativeBackground(),
)When to use each
| Widget | Use case |
Semantics(label:) | Custom widgets that lack built-in semantics (raw GestureDetector, Container with onTap) |
Semantics(button: true) | Custom buttons not using Material ElevatedButton/TextButton |
Semantics(header: true) | Section headers (category names in a catalog) |
Semantics(image: true, label:) | Product/content images |
MergeSemantics | Icon + text pairs, price + currency pairs |
ExcludeSemantics | Purely decorative images, background gradients, dividers |
Material widgets (ElevatedButton, TextField, Checkbox) already have built-in semantics. Do NOT double-wrap them unless overriding the default label.
2. Color Contrast
Follow WCAG 2.1 minimum contrast ratios:
| Element | Minimum ratio |
| Normal text (< 18sp) | 4.5:1 |
| Large text (>= 18sp or >= 14sp bold) | 3.0:1 |
| UI components & graphical objects | 3.0:1 |
Verification
- Use the Accessibility Scanner on Android (Settings > Accessibility)
- Run Lighthouse audit in Chrome DevTools for the web build
- Use online contrast checkers (WebAIM Contrast Checker) with hex values from
ds_colors.dart
Violations that show up again and again
- Light gray text on white backgrounds for secondary info (descriptions, prices in light theme)
- Disabled button text that falls below 3.0:1
- Placeholder text in search fields
When fixing, update colors in design_system/ tokens so the fix propagates everywhere.
3. Tap Targets
All interactive elements must be at least 48x48 logical pixels:
// BAD - icon button too small
GestureDetector(
onTap: onAdd,
child: Icon(Icons.add, size: 24),
)
// GOOD - ensure minimum hit area
IconButton(
onPressed: onAdd,
icon: Icon(Icons.add, size: 24),
// IconButton already enforces 48x48 by default
)
// GOOD - for custom widgets, use constraints
GestureDetector(
onTap: onAdd,
child: ConstrainedBox(
constraints: const BoxConstraints(minWidth: 48, minHeight: 48),
child: Center(child: Icon(Icons.add, size: 24)),
),
)Spacing between targets
Adjacent tap targets must have enough spacing to avoid accidental taps. Minimum 8px gap between interactive elements.
4. Screen Reader Support
Labels for images (product photos, avatars, thumbnails)
// Product image in a catalog
Semantics(
image: true,
label: 'Foto do produto: ${product.name}',
child: CachedNetworkImage(
imageUrl: product.imageUrl,
// ...
),
)
// Decorative images (backgrounds, patterns)
ExcludeSemantics(
child: Image.asset('assets/background_pattern.png'),
)Labels for icon buttons
IconButton(
icon: Icon(Icons.shopping_cart),
tooltip: 'Ver carrinho', // tooltip doubles as semantic label
onPressed: () => openCart(),
)Price announcements
// Announce price clearly
MergeSemantics(
child: Row(
children: [
Text('R\$'),
Text('29,90'),
],
),
)
// Screen reader announces: "R$ 29,90"5. Web Accessibility (any web build)
Flutter web disables semantics by default for performance. For customer-facing apps this is unacceptable.
Enable semantics in web builds
In the app's web/index.html, add before the Flutter loader script:
<script>
// Enable accessibility for Flutter web
window.flutterConfiguration = {
canvasKitBaseUrl: '/canvaskit/',
};
</script>In the app's main.dart:
import 'package:flutter/semantics.dart';
void main() {
// Force enable semantics for web accessibility
WidgetsFlutterBinding.ensureInitialized();
SemanticsBinding.instance.ensureSemantics();
runApp(const MyApp());
}Alternative: enable via URL parameter
For testing, append ?semantics=true to the web URL to activate the semantics tree without code changes.
Web-specific considerations
- Ensure the HTML
<title>tag is descriptive (e.g., "Product Catalog — Acme") - Add
lang="pt-BR"to the<html>tag inindex.html - Flutter web renders to canvas, so ALL accessibility depends on the Semantics tree being correct
6. Font Scaling
Support dynamic text sizing for users who increase system font size:
// BAD - breaks with large fonts
SizedBox(
height: 48,
child: Text('Categoria', style: TextStyle(fontSize: 16)),
)
// GOOD - adapt to text scale
ConstrainedBox(
constraints: const BoxConstraints(minHeight: 48),
child: Text('Categoria', style: TextStyle(fontSize: 16)),
)Guidelines
- Use
minHeight/minWidthinstead of fixedheight/widthfor containers holding text - Test with system font scale at 2.0x (Settings > Display > Font size)
- Ensure text does not overflow or get clipped — use
Flexible,Expanded, oroverflow: TextOverflow.ellipsiswithmaxLines - Product names and descriptions must remain readable at large scales
Limiting scale when necessary
Only limit scale factor for truly constrained UI (e.g., small price badges):
MediaQuery.withClampedTextScaling(
minScaleFactor: 1.0,
maxScaleFactor: 1.5,
child: PriceBadge(...),
)7. Focus Management (Web)
Keyboard navigation is essential for web accessibility:
// Ensure custom interactive widgets can receive focus
Focus(
child: GestureDetector(
onTap: onTap,
child: MenuItemCard(...),
),
)
// Set logical focus traversal order
FocusTraversalGroup(
policy: OrderedTraversalPolicy(),
child: Column(
children: [
FocusTraversalOrder(
order: NumericFocusOrder(1),
child: SearchBar(),
),
FocusTraversalOrder(
order: NumericFocusOrder(2),
child: CategoryFilter(),
),
FocusTraversalOrder(
order: NumericFocusOrder(3),
child: ProductGrid(),
),
],
),
)Keyboard shortcuts for the web build
- Tab — move between interactive elements
- Enter/Space — activate buttons
- Escape — close modals/bottom sheets
Ensure all modals trap focus (Material showDialog and showModalBottomSheet do this automatically).
8. Accessible Images
Every meaningful image needs descriptive text:
// Product image
Semantics(
image: true,
label: product.name, // "Pizza Margherita"
child: ProductImage(url: product.imageUrl),
)
// Category icon
Semantics(
image: true,
label: 'Categoria: ${category.name}',
child: CategoryIcon(icon: category.icon),
)
// Restaurant logo
Semantics(
image: true,
label: 'Logo do restaurante ${restaurant.name}',
child: RestaurantLogo(url: restaurant.logoUrl),
)
// Decorative divider — exclude
ExcludeSemantics(
child: Image.asset('assets/divider_ornament.png'),
)9. Accessible Forms
Forms (search, checkout, sign-up) must announce labels and errors:
TextFormField(
decoration: InputDecoration(
labelText: 'Nome completo', // announced by screen reader
hintText: 'Digite seu nome',
errorText: hasError ? 'Nome e obrigatorio' : null, // announced on error
),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Nome e obrigatorio'; // announced when validation fails
}
return null;
},
)Guidelines
- Always use
labelTextonInputDecoration, not justhintText(hints disappear on focus) - Error messages must be descriptive: say what is wrong, not just "campo invalido"
- After form submission with errors, move focus to the first field with an error
- Group related fields with
MergeSemanticsorSemantics(label:)when context is needed
10. Audit Workflow
When mode is audit
- Scan widgets for missing
Semanticson:- Images (
Image,CachedNetworkImage,SvgPicture) - Custom buttons (
GestureDetector,InkWellwithoutSemantics) - Icon-only buttons without
tooltip - Decorative elements that should use
ExcludeSemantics
- Images (
- Check tap target sizes — find interactive widgets with constrained sizes below 48x48
- Review color usage — cross-reference text colors against background colors in the design system tokens
- Check web semantics — verify
SemanticsBinding.instance.ensureSemantics()is called in every web build - Check font scaling — find fixed
height/widthon containers holding text - Produce report in this format:
## Accessibility Audit: [app_name]
### Critical (must fix)
- [ ] Issue description — file:line
### Important (should fix)
- [ ] Issue description — file:line
### Minor (nice to have)
- [ ] Issue description — file:lineManual testing checklist
| Platform | Tool | How to test |
| Android | TalkBack | Settings > Accessibility > TalkBack. Navigate the app with swipe gestures. |
| iOS | VoiceOver | Settings > Accessibility > VoiceOver. Swipe to navigate. |
| macOS | VoiceOver | Cmd+F5. Use arrow keys to navigate web apps in Safari/Chrome. |
| Web | Lighthouse | Chrome DevTools > Lighthouse > Accessibility. Target score >= 90. |
| Web | axe DevTools | Chrome extension. Finds WCAG violations in rendered page. |
| Web | Tab navigation | Press Tab through the entire checkout/browse flow without using a mouse. |
Lighthouse audit for the web build
# Run Lighthouse CI from command line
npx lighthouse http://localhost:PORT --only-categories=accessibility --output=json --output-path=./a11y-report.jsonTarget: Lighthouse accessibility score >= 90 for the web build.
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.

