prefer-action-button-tooltip
- Group
- Accessibility
- Path
lint/a11y/prefer-action-button-tooltip- Default
- Off, opt in
- Origin
- Falcon
- Domain
- flutter
- Rule
- 311 of 512
Requires useful tooltips on Flutter floating action buttons and icon buttons.
Tooltips describe actions to assistive technology. Resolved Flutter
FloatingActionButton (unnamed, small, large, extended) and IconButton (unnamed,
filled, filledTonal, outlined) constructors are checked. Missing, literal null,
and empty non-interpolated string tooltips are reported. Dynamic labels and
other button APIs are not guessed; custom classes and shadowed names are ignored.
This checks the button's own tooltip argument, including extended FABs;
labels or enclosing Tooltip/Semantics widgets do not exempt the button.
Invalid
import 'package:flutter/material.dart';
import 'package:flutter/material.dart' as m;
Widget missing() => FloatingActionButton(onPressed: () {});
Widget empty() => FloatingActionButton(tooltip: '', onPressed: () {});
Widget nullLabel() => new FloatingActionButton(tooltip: null, onPressed: () {});
Widget prefixed() => m.FloatingActionButton.small(onPressed: () {});
Widget extended() => FloatingActionButton.extended(label: Text('Add'), onPressed: () {});
Widget icon() => IconButton(icon: Icon(Icons.add), onPressed: () {});
Widget filled() => IconButton.filled(tooltip: r'', icon: Icon(Icons.add), onPressed: () {});
Widget constant() => const FloatingActionButton(onPressed: null);
Widget adjacent() => FloatingActionButton(tooltip: '' '', onPressed: () {});
Widget large() => FloatingActionButton.large(onPressed: () {});
Widget outlined() => IconButton.outlined(icon: Icon(Icons.add), onPressed: () {});
Widget tonal() => IconButton.filledTonal(icon: Icon(Icons.add), onPressed: () {});
Widget wrapped() => Tooltip(
message: 'Add',
child: IconButton(icon: Icon(Icons.add), onPressed: () {}),
);
Widget iconLabel() => IconButton(icon: Icon(Icons.add, semanticLabel: 'Add'), onPressed: () {}); Widget missing() => FloatingActionButton(onPressed: () {});Widget missing() => FloatingActionButton(onPressed: () {});Widget empty() => FloatingActionButton(tooltip: '', onPressed: () {});Widget empty() => FloatingActionButton(tooltip: '', onPressed: () {});Widget nullLabel() => new FloatingActionButton(tooltip: null, onPressed: () {});Widget nullLabel() => new FloatingActionButton(tooltip: null, onPressed: () {});Widget prefixed() => m.FloatingActionButton.small(onPressed: () {});Widget prefixed() => m.FloatingActionButton.small(onPressed: () {});Widget extended() => FloatingActionButton.extended(label: Text('Add'), onPressed: () {});Widget extended() => FloatingActionButton.extended(label: Text('Add'), onPressed: () {});Widget icon() => IconButton(icon: Icon(Icons.add), onPressed: () {});Widget icon() => IconButton(icon: Icon(Icons.add), onPressed: () {});Widget filled() => IconButton.filled(tooltip: r'', icon: Icon(Icons.add), onPressed: () {});Widget filled() => IconButton.filled(tooltip: r'', icon: Icon(Icons.add), onPressed: () {});Widget constant() => const FloatingActionButton(onPressed: null);Widget constant() => const FloatingActionButton(onPressed: null);Widget adjacent() => FloatingActionButton(tooltip: '' '', onPressed: () {});Widget adjacent() => FloatingActionButton(tooltip: '' '', onPressed: () {});Widget large() => FloatingActionButton.large(onPressed: () {});Widget large() => FloatingActionButton.large(onPressed: () {});Widget outlined() => IconButton.outlined(icon: Icon(Icons.add), onPressed: () {});Widget outlined() => IconButton.outlined(icon: Icon(Icons.add), onPressed: () {});Widget tonal() => IconButton.filledTonal(icon: Icon(Icons.add), onPressed: () {}); message: 'Add', child: IconButton(icon: Icon(Icons.add), onPressed: () {}),);Widget iconLabel() => IconButton(icon: Icon(Icons.add, semanticLabel: 'Add'), onPressed: () {});Valid
import 'package:flutter/material.dart';
import 'package:flutter/material.dart' as m;
Widget labeled() => FloatingActionButton(tooltip: 'Add', onPressed: () {});
Widget iconLabeled() => IconButton(tooltip: 'Add', icon: Icon(Icons.add), onPressed: () {});
Widget unknown(String? label) => FloatingActionButton(tooltip: label, onPressed: () {});
Widget interpolated(String label) => FloatingActionButton(tooltip: '$label', onPressed: () {});
Widget otherButton() => TextButton(child: Text('Add'), onPressed: () {});
Widget shadowed(dynamic FloatingActionButton) => FloatingActionButton(onPressed: () {});
Widget prefixShadow(dynamic m) => m.FloatingActionButton(onPressed: () {});
Widget nestedShadow(dynamic IconButton) => Tooltip(message: 'Add', child: IconButton(onPressed: () {}));
Widget localCustom() => CustomActionButton();
class CustomActionButton extends StatelessWidget {
Widget build(BuildContext context) => const SizedBox();
}Configure prefer-action-button-tooltip
Set its severity in falcon.json. See the configuration guide.
{
"linter": {
"rules": {
"a11y": {
"prefer-action-button-tooltip": "error"
}
}
}
}Or silence one occurrence with a suppression comment; the reason is required.
// falcon-ignore lint/a11y/prefer-action-button-tooltip: <reason>More accessibility rules
- accessible-widget-labelsflutter
Warn about unlabeled interactive gesture targets.
- avoid-missing-image-altflutter
Requires semanticLabel on Flutter Image and imageSemanticLabel on
FadeInImage. - minimum-touch-targetflutter
Warn about explicitly undersized Flutter touch targets.