Mode d’emploi
- Copiez la commande et examinez le paquet avant de l’installer dans votre environnement agent.
- Consultez le document original pour les outils, identifiants et environnements requis.
- Décrivez les entrées et le livrable souhaité ; comparez la sortie aux sources.
npx skills add https://github.com/thesimpleapp/flutter-app-skills --skill flutter-improving-accessibilityAvant de commencer
- L’installation n’inclut ni abonnement au modèle, ni quota API, ni accès aux fichiers.
- Étoiles et installations reflètent l’activité, pas un test indépendant de qualité ou de sécurité.
Rendu depuis le dépôt source en conservant titres, exemples, code, tableaux, liens et images.
Flutter accessibility
Prefer built-in Material and Cupertino widgets — they already emit a TalkBack / VoiceOver / JAWS / NVDA tree. Add Semantics (or Semantics.fromProperties) only on custom painted or gestured widgets.
If this repo already has a Semantics helper, a11y test harness, labeled-control convention, or a pressable with semanticLabel, extend that. Do not wrap it in a second Semantics(label:) that repeats visible text.
Official: Accessibility, assistive technologies, UI design and styling, accessibility testing.
References
Read references/recipes.md when implementing a custom control, merge/exclude/block, MediaQuery wiring, or the guideline test.
Detect first
Search the repo for Semantics(, MergeSemantics, ExcludeSemantics, BlockSemantics, semanticLabel, excludeFromSemantics, tooltip:, meetsGuideline(, ensureSemantics(, highContrastTheme, accessibleNavigationOf, textScalerOf. Open a nearby production screen and copy that pattern.
Hard rules
Semantics
- Custom paint /
GestureDetector/InkWell: setlabel, a role flag (button,slider,textField),tooltip/hint, andonTapso the node is announced as a control. - Role is a flag:
Semantics(button: true, label: 'Submit'). Never put "button" in the label.label/hint/tooltiprequire an ambientDirectionalityor an explicittextDirection. Transient status:liveRegion: true. container: trueintroduces aSemanticsNode— use it for a distinct TalkBack/VoiceOver focus stop.
Merge, exclude, block
- One control + its visible
Text: wrap both inMergeSemantics. Never merge two checkboxes, two tappable children, or conflictingselected/checkedvalues. ExcludeSemanticsonly for decorative or redundant descendants.Semantics(excludeSemantics: true)replaces all child semantics with this node. Hide widgets painted behind a modal orDrawerwithBlockSemanticson the overlay, notExcludeSemanticson the overlay child.
Hit targets and names
- Every tappable target ≥ 48×48 logical pixels (
kMinInteractiveDimension). Cupertino floor iskMinInteractiveDimensionCupertino(44.0). PreferIconButtonso the hit region stays 48 regardless oficonSize. Do not passIconButton.constraintsor compactVisualDensitythat shrinks below 48. - Icon-only
IconButton/ FAB:tooltipis a short action name. Custom icon taps:Semantics(label: ..., button: true). DecorativeIcon:semanticLabel. MeaningfulImage:semanticLabel. DecorativeImage:excludeFromSemantics: true.
Text scale
- Read with
MediaQuery.textScalerOf(context)and compute sizes withtextScaler.scale(fontSize). NevertextScaleFactor— deprecated and cannot represent Android 14 nonlinear scaling. Textalready honors the OS font-size setting. Test every screen on a small device at the largest OS text size.MediaQuery.withNoTextScalingonly to stop icon fonts from scaling. Never disable scaling at theMaterialApproot.
MediaQuery flags
- Call
MediaQuery.accessibleNavigationOf,highContrastOf,disableAnimationsOf, andtextScalerOf— notMediaQuery.of. - When
accessibleNavigationOfis true, disable timeouts or raise their minimum duration. - When
highContrastOfis true, setMaterialApp.highContrastThemeandhighContrastDarkTheme. Wrapping a subtree inMediaQuery(data: copyWith(highContrast: true))does not switch those themes. disableAnimationsOfis Android Remove animations.AnimationControlleralready honorsSemanticsBinding.disableAnimations. Custom explicit animations must still readdisableAnimationsOf. iOS Reduce Motion isAccessibilityFeatures.reduceMotionand does not setdisableAnimations.
Traversal
- TalkBack/VoiceOver sibling order:
Semantics(sortKey: OrdinalSortKey(n)). Keyboard/Tab order is a different tree:FocusTraversalGroup/FocusTraversalOrder. Do not usesortKeyto fix Tab order.
Contrast
- At least 4.5:1 between text/controls and background (except disabled). 3.0:1 for large text (18pt+ regular or 14pt+ bold). Do not convey state by color alone.
Tests and devices
tester.ensureSemantics(), thenexpectLater(tester, meetsGuideline(...)), thenhandle.dispose(). Guidelines:androidTapTargetGuideline,iOSTapTargetGuideline,labeledTapTargetGuideline,textContrastGuideline.- Walk every changed screen with TalkBack and VoiceOver. Flutter web:
SemanticsBinding.instance.ensureSemantics()inmain(). Debug withshowSemanticsDebuggerorflutter run -d chrome --profile --dart-define=FLUTTER_WEB_DEBUG_SHOW_SEMANTICS=true.
Samples
Semantics(
button: true,
label: 'Submit',
hint: 'Sends the form',
onTap: onSubmit,
child: CustomPaint(painter: SubmitPainter()),
)
IconButton(
tooltip: 'Search',
icon: const Icon(Icons.search),
onPressed: onSearch,
)
final TextScaler scaler = MediaQuery.textScalerOf(context);
final bool screenReader = MediaQuery.accessibleNavigationOf(context);Do not
- Wrap an already-semantic Material/Cupertino widget in
Semantics(label:)that repeats visible text. - Put
ExcludeSemanticsaround interactive content, or use it instead ofBlockSemanticsto hide widgets behind a dialog. MergeSemanticsover two checkboxes or two tappable children.- Icon-only control with no
tooltip, noSemantics.label, and noIcon.semanticLabel. MediaQuery.of(context).textScaleFactororText(textScaleFactor:).- Disable text scaling at the app root, or shrink
IconButtonbelow 48. - Assume
MediaQuery(data: copyWith(disableAnimations: true))stopsAnimationController. - Write the role into the label (
label: 'Submit button'). - Use
Semantics.sortKeyto fix keyboard Tab order.
Fix a screen
- Detect the existing a11y convention and reuse it.
- Leave stock Material/Cupertino widgets unlabeled unless they are custom-painted or icon-only.
- Give every icon-only control a
tooltiporSemantics(label:, button: true). Pad the hit target to 48, not the glyph. - Read
MediaQuery.*Of. Honor largest text, high-contrast themes, screen-reader timeouts, and reduced motion. - Add the guideline test. Walk TalkBack and VoiceOver.
Verify
tester.ensureSemantics()+ the fourmeetsGuidelinechecks +handle.dispose()on the screen you touched.- Layout still fits at the OS largest text size on a small device.
- Contrast ≥ 4.5:1 (3:1 large text); state is not color-only.
- TalkBack and VoiceOver: every control has an intelligible name and the right role.
- Web: semantics enabled from
main().



