-
Initialize Web Accessibility (If Applicable)
For web targets, accessibility is disabled by default for performance. Force enable it at the entry point.
import 'package:flutter/foundation.dart';
import 'package:flutter/semantics.dart';
void main() {
runApp(const MyApp());
if (kIsWeb) {
SemanticsBinding.instance.ensureSemantics();
}
}
-
Apply Semantic Annotations
Use Semantics, MergeSemantics, and ExcludeSemantics to build a clean accessibility tree. For custom web components, explicitly define the SemanticsRole.
Semantics(
role: SemanticsRole.button,
label: 'Submit Form',
hint: 'Press to send your application',
button: true,
child: GestureDetector(
onTap: _submit,
child: const CustomButtonUI(),
),
)
-
Enforce Tap Target and Contrast Standards
Ensure all interactive elements meet the 48x48 dp minimum (Android) or 44x44 pt minimum (iOS/Web).
// Example of enforcing minimum tap target size
ConstrainedBox(
constraints: const BoxConstraints(
minWidth: 48.0,
minHeight: 48.0,
),
child: IconButton(
icon: const Icon(Icons.info),
onPressed: () {},
tooltip: 'Information', // Tooltip.message follows Tooltip.child in semantics tree
),
)
-
Implement Adaptive Layouts
Use LayoutBuilder to respond to available space rather than device type.
LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth > 600) {
return const WideDesktopLayout();
} else {
return const NarrowMobileLayout();
}
},
)
-
Implement Keyboard and Mouse Support
Use FocusableActionDetector for custom controls to handle focus, hover, and keyboard shortcuts simultaneously.
FocusableActionDetector(
onFocusChange: (hasFocus) => setState(() => _hasFocus = hasFocus),
onShowHoverHighlight: (hasHover) => setState(() => _hasHover = hasHover),
actions: <Type, Action<Intent>>{
ActivateIntent: CallbackAction<Intent>(
onInvoke: (intent) {
_performAction();
return null;
},
),
},
child: MouseRegion(
cursor: SystemMouseCursors.click,
child: CustomWidget(isHovered: _hasHover, isFocused: _hasFocus),
),
)
-
Manage Focus Traversal
Group related widgets using FocusTraversalGroup to ensure logical tab order for keyboard users.
FocusTraversalGroup(
policy: OrderedTraversalPolicy(),
child: Column(
children: [
FocusTraversalOrder(
order: const NumericFocusOrder(1.0),
child: TextField(),
),
FocusTraversalOrder(
order: const NumericFocusOrder(2.0),
child: ElevatedButton(onPressed: () {}, child: Text('Submit')),
),
],
),
)
-
Validate Accessibility via Automated Tests
STOP AND ASK THE USER: "Would you like me to generate widget tests to validate accessibility guidelines (contrast, tap targets) for your UI?"
If yes, implement the AccessibilityGuideline API in the test suite:
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('Validates a11y guidelines', (WidgetTester tester) async {
final SemanticsHandle handle = tester.ensureSemantics();
await tester.pumpWidget(const MyApp());
await expectLater(tester, meetsGuideline(androidTapTargetGuideline));
await expectLater(tester, meetsGuideline(iOSTapTargetGuideline));
await expectLater(tester, meetsGuideline(labeledTapTargetGuideline));
await expectLater(tester, meetsGuideline(textContrastGuideline));
handle.dispose();
});
}