accessible-widget-labels
- Group
- Accessibility
- Path
lint/a11y/accessible-widget-labels- Default
- Off, opt in
- Origin
- Falcon
- Domain
- flutter
- Rule
- 1 of 512
Warn about unlabeled interactive gesture targets.
Checks resolved Flutter GestureDetector, InkWell, and InkResponse constructors.
Direct Text children, Icon semanticLabel, or Semantics/Tooltip ancestors with
plain or rich labels supply labels. Inert/excluded gestures and unknown/custom
children are skipped. Dynamic labels are accepted; null and empty literals are not.
This is a local heuristic, not compliance validation. Image labels and action
button tooltips are covered by avoid-missing-image-alt and
prefer-action-button-tooltip respectively.
Invalid
import 'package:flutter/material.dart';
import 'package:flutter/material.dart' as f;
void actions() {
GestureDetector(onTap: () {});
f.InkWell(onTap: () {}, child: Icon(null));
InkResponse(onTap: () {}, child: Text(' '));
GestureDetector(onTap: () {}, child: Icon(null));
InkWell(onTap: () {}, child: Text(''));
InkResponse(onTap: () {});
Tooltip(message: '', child: InkWell(onTap: () {}));
Tooltip(richMessage: null, child: InkWell(onTap: () {}));
Tooltip(richMessage: (null), child: InkResponse(onTap: () {}));
Semantics(attributedLabel: null, child: InkWell(onTap: () {}));
Semantics(attributedLabel: (null), child: InkResponse(onTap: () {}));
}
void shadowed(dynamic Tooltip, dynamic Semantics) {
Tooltip(richMessage: 'Delete', child: InkWell(onTap: () {}));
Semantics(attributedLabel: 'Delete', child: InkResponse(onTap: () {}));
}
void siblings(dynamic richMessage, dynamic attributedLabel) {
Tooltip(richMessage: richMessage, child: InkWell(onTap: () {}));
InkWell(onTap: () {});
Semantics(attributedLabel: attributedLabel, child: InkResponse(onTap: () {}));
InkResponse(onTap: () {});
}
void additionalGestures(dynamic callback) {
GestureDetector(onSecondaryTapCancel: callback);
GestureDetector(onTertiaryTapCancel: callback);
GestureDetector(onLongPressCancel: callback);
GestureDetector(onSecondaryLongPressDown: callback);
GestureDetector(onSecondaryLongPressCancel: callback);
GestureDetector(onSecondaryLongPress: callback);
GestureDetector(onSecondaryLongPressStart: callback);
GestureDetector(onSecondaryLongPressMoveUpdate: callback);
GestureDetector(onSecondaryLongPressUp: callback);
GestureDetector(onSecondaryLongPressEnd: callback);
GestureDetector(onTertiaryLongPressDown: callback);
GestureDetector(onTertiaryLongPressCancel: callback);
GestureDetector(onTertiaryLongPress: callback);
GestureDetector(onTertiaryLongPressStart: callback);
GestureDetector(onTertiaryLongPressMoveUpdate: callback);
GestureDetector(onTertiaryLongPressUp: callback);
GestureDetector(onTertiaryLongPressEnd: callback);
GestureDetector(onVerticalDragDown: callback);
GestureDetector(onVerticalDragCancel: callback);
GestureDetector(onHorizontalDragDown: callback);
GestureDetector(onHorizontalDragCancel: callback);
GestureDetector(onForcePressStart: callback);
GestureDetector(onForcePressPeak: callback);
GestureDetector(onForcePressUpdate: callback);
GestureDetector(onForcePressEnd: callback);
GestureDetector(onPanCancel: callback);
f.GestureDetector(onTapMove: (_) {}, onTap: callback);
GestureDetector(onSecondaryLongPress: () {});
InkWell(onSecondaryTapCancel: () {}, onSecondaryTapDown: callback);
InkResponse(onSecondaryTapCancel: (callback), onSecondaryTap: () {});
}
void inkEnablingCallbacks(dynamic callback) {
InkWell(onTap: callback);
InkWell(onTapDown: callback);
InkWell(onTapUp: callback);
InkWell(onDoubleTap: callback);
InkWell(onLongPress: callback);
InkWell(onLongPressUp: callback);
InkWell(onSecondaryTap: callback);
InkWell(onSecondaryTapDown: callback);
InkWell(onSecondaryTapUp: callback);
InkResponse(onTap: callback);
InkResponse(onTapDown: callback);
InkResponse(onTapUp: callback);
InkResponse(onDoubleTap: callback);
InkResponse(onLongPress: callback);
InkResponse(onLongPressUp: callback);
InkResponse(onSecondaryTap: callback);
InkResponse(onSecondaryTapDown: callback);
InkResponse(onSecondaryTapUp: callback);
GestureDetector(onTapCancel: callback);
InkWell(onTapCancel: callback, onTap: () {});
InkResponse(onTapCancel: () {}, onTapUp: callback);
}void actions() { GestureDetector(onTap: () {}); GestureDetector(onTap: () {}); f.InkWell(onTap: () {}, child: Icon(null)); f.InkWell(onTap: () {}, child: Icon(null)); InkResponse(onTap: () {}, child: Text(' ')); InkResponse(onTap: () {}, child: Text(' ')); GestureDetector(onTap: () {}, child: Icon(null)); GestureDetector(onTap: () {}, child: Icon(null)); InkWell(onTap: () {}, child: Text('')); InkWell(onTap: () {}, child: Text('')); InkResponse(onTap: () {}); InkResponse(onTap: () {}); Tooltip(message: '', child: InkWell(onTap: () {})); Tooltip(message: '', child: InkWell(onTap: () {})); Tooltip(richMessage: null, child: InkWell(onTap: () {})); Tooltip(richMessage: null, child: InkWell(onTap: () {})); Tooltip(richMessage: (null), child: InkResponse(onTap: () {})); Tooltip(richMessage: (null), child: InkResponse(onTap: () {})); Semantics(attributedLabel: null, child: InkWell(onTap: () {})); Semantics(attributedLabel: null, child: InkWell(onTap: () {})); Semantics(attributedLabel: (null), child: InkResponse(onTap: () {}));void shadowed(dynamic Tooltip, dynamic Semantics) { Tooltip(richMessage: 'Delete', child: InkWell(onTap: () {})); Tooltip(richMessage: 'Delete', child: InkWell(onTap: () {})); Semantics(attributedLabel: 'Delete', child: InkResponse(onTap: () {})); Tooltip(richMessage: richMessage, child: InkWell(onTap: () {})); InkWell(onTap: () {}); Semantics(attributedLabel: attributedLabel, child: InkResponse(onTap: () {})); InkResponse(onTap: () {});void additionalGestures(dynamic callback) { GestureDetector(onSecondaryTapCancel: callback); GestureDetector(onSecondaryTapCancel: callback); GestureDetector(onTertiaryTapCancel: callback); GestureDetector(onTertiaryTapCancel: callback); GestureDetector(onLongPressCancel: callback); GestureDetector(onLongPressCancel: callback); GestureDetector(onSecondaryLongPressDown: callback); GestureDetector(onSecondaryLongPressDown: callback); GestureDetector(onSecondaryLongPressCancel: callback); GestureDetector(onSecondaryLongPressCancel: callback); GestureDetector(onSecondaryLongPress: callback); GestureDetector(onSecondaryLongPress: callback); GestureDetector(onSecondaryLongPressStart: callback); GestureDetector(onSecondaryLongPressStart: callback); GestureDetector(onSecondaryLongPressMoveUpdate: callback); GestureDetector(onSecondaryLongPressMoveUpdate: callback); GestureDetector(onSecondaryLongPressUp: callback); GestureDetector(onSecondaryLongPressUp: callback); GestureDetector(onSecondaryLongPressEnd: callback); GestureDetector(onSecondaryLongPressEnd: callback); GestureDetector(onTertiaryLongPressDown: callback); GestureDetector(onTertiaryLongPressDown: callback); GestureDetector(onTertiaryLongPressCancel: callback); GestureDetector(onTertiaryLongPressCancel: callback); GestureDetector(onTertiaryLongPress: callback); GestureDetector(onTertiaryLongPress: callback); GestureDetector(onTertiaryLongPressStart: callback); GestureDetector(onTertiaryLongPressStart: callback); GestureDetector(onTertiaryLongPressMoveUpdate: callback); GestureDetector(onTertiaryLongPressMoveUpdate: callback); GestureDetector(onTertiaryLongPressUp: callback); GestureDetector(onTertiaryLongPressUp: callback); GestureDetector(onTertiaryLongPressEnd: callback); GestureDetector(onTertiaryLongPressEnd: callback); GestureDetector(onVerticalDragDown: callback); GestureDetector(onVerticalDragDown: callback); GestureDetector(onVerticalDragCancel: callback); GestureDetector(onVerticalDragCancel: callback); GestureDetector(onHorizontalDragDown: callback); GestureDetector(onHorizontalDragDown: callback); GestureDetector(onHorizontalDragCancel: callback); GestureDetector(onHorizontalDragCancel: callback); GestureDetector(onForcePressStart: callback); GestureDetector(onForcePressStart: callback); GestureDetector(onForcePressPeak: callback); GestureDetector(onForcePressPeak: callback); GestureDetector(onForcePressUpdate: callback); GestureDetector(onForcePressUpdate: callback); GestureDetector(onForcePressEnd: callback); GestureDetector(onForcePressEnd: callback); GestureDetector(onPanCancel: callback); GestureDetector(onPanCancel: callback); f.GestureDetector(onTapMove: (_) {}, onTap: callback); f.GestureDetector(onTapMove: (_) {}, onTap: callback); GestureDetector(onSecondaryLongPress: () {}); GestureDetector(onSecondaryLongPress: () {}); InkWell(onSecondaryTapCancel: () {}, onSecondaryTapDown: callback); InkWell(onSecondaryTapCancel: () {}, onSecondaryTapDown: callback); InkResponse(onSecondaryTapCancel: (callback), onSecondaryTap: () {});void inkEnablingCallbacks(dynamic callback) { InkWell(onTap: callback); InkWell(onTap: callback); InkWell(onTapDown: callback); InkWell(onTapDown: callback); InkWell(onTapUp: callback); InkWell(onTapUp: callback); InkWell(onDoubleTap: callback); InkWell(onDoubleTap: callback); InkWell(onLongPress: callback); InkWell(onLongPress: callback); InkWell(onLongPressUp: callback); InkWell(onLongPressUp: callback); InkWell(onSecondaryTap: callback); InkWell(onSecondaryTap: callback); InkWell(onSecondaryTapDown: callback); InkWell(onSecondaryTapDown: callback); InkWell(onSecondaryTapUp: callback); InkWell(onSecondaryTapUp: callback); InkResponse(onTap: callback); InkResponse(onTap: callback); InkResponse(onTapDown: callback); InkResponse(onTapDown: callback); InkResponse(onTapUp: callback); InkResponse(onTapUp: callback); InkResponse(onDoubleTap: callback); InkResponse(onDoubleTap: callback); InkResponse(onLongPress: callback); InkResponse(onLongPress: callback); InkResponse(onLongPressUp: callback); InkResponse(onLongPressUp: callback); InkResponse(onSecondaryTap: callback); InkResponse(onSecondaryTap: callback); InkResponse(onSecondaryTapDown: callback); InkResponse(onSecondaryTapDown: callback); InkResponse(onSecondaryTapUp: callback); InkResponse(onSecondaryTapUp: callback); GestureDetector(onTapCancel: callback); GestureDetector(onTapCancel: callback); InkWell(onTapCancel: callback, onTap: () {}); InkWell(onTapCancel: callback, onTap: () {}); InkResponse(onTapCancel: () {}, onTapUp: callback);Valid
import 'package:flutter/material.dart';
import 'package:flutter/material.dart' as f;
void actions(String label) {
IconButton(tooltip: 'Add');
f.IconButton.filled(tooltip: label);
FloatingActionButton(child: Text('Add'));
GestureDetector(onTap: () {}, child: Text('Open'));
InkWell(onTap: () {}, child: Icon(null, semanticLabel: 'Open'));
Semantics(label: 'Open', child: InkResponse(onTap: () {}));
Tooltip(message: 'Add', child: IconButton());
GestureDetector(excludeFromSemantics: true);
TextButton(child: Text('Save'));
GestureDetector();
InkWell(onTap: null);
InkResponse();
IconButton(icon: customLabel());
GestureDetector(onTap: () {}, child: customLabel());
}
void shadow(dynamic IconButton) { IconButton(); }
Widget customLabel() => Text('Custom label');
void alternatives(dynamic richMessage, dynamic attributedLabel) {
Tooltip(richMessage: TextSpan(text: 'Delete'), child: InkWell(onTap: () {}, child: Icon(null)));
Semantics(attributedLabel: AttributedString('Delete'), child: InkResponse(onTap: () {}, child: Icon(null)));
f.Tooltip(richMessage: (richMessage), child: f.GestureDetector(onTap: () {}, child: f.Icon(null)));
f.Semantics(attributedLabel: (attributedLabel), child: f.InkWell(onTap: () {}, child: f.Icon(null)));
Tooltip(message: 'Delete', richMessage: null, child: InkWell(onTap: () {}));
Semantics(label: 'Delete', attributedLabel: null, child: InkResponse(onTap: () {}));
}
void inactiveAdditionalGestures() {
GestureDetector(onTapMove: (null));
GestureDetector(onSecondaryTapCancel: null);
GestureDetector(onTertiaryTapCancel: null);
GestureDetector(onLongPressCancel: null);
GestureDetector(onSecondaryLongPressDown: null);
GestureDetector(onSecondaryLongPressCancel: null);
GestureDetector(onSecondaryLongPress: ((null)));
GestureDetector(onSecondaryLongPressStart: null);
GestureDetector(onSecondaryLongPressMoveUpdate: null);
GestureDetector(onSecondaryLongPressUp: null);
GestureDetector(onSecondaryLongPressEnd: null);
GestureDetector(onTertiaryLongPressDown: null);
GestureDetector(onTertiaryLongPressCancel: null);
GestureDetector(onTertiaryLongPress: null);
GestureDetector(onTertiaryLongPressStart: null);
GestureDetector(onTertiaryLongPressMoveUpdate: null);
GestureDetector(onTertiaryLongPressUp: null);
GestureDetector(onTertiaryLongPressEnd: null);
GestureDetector(onVerticalDragDown: null);
GestureDetector(onVerticalDragCancel: null);
GestureDetector(onHorizontalDragDown: null);
GestureDetector(onHorizontalDragCancel: null);
GestureDetector(onForcePressStart: null);
GestureDetector(onForcePressPeak: null);
GestureDetector(onForcePressUpdate: null);
GestureDetector(onForcePressEnd: null);
GestureDetector(onPanCancel: null);
InkWell(onSecondaryTapCancel: (null));
InkResponse(onSecondaryTapCancel: null);
InkWell(onHover: (_) {}, onFocusChange: (_) {}, onHighlightChanged: (_) {});
InkResponse(onHover: (_) {}, onFocusChange: (_) {}, onHighlightChanged: (_) {});
GestureDetector(onSecondaryLongPress: () {}, child: Text('Open'));
Tooltip(message: 'Open', child: GestureDetector(onTapMove: (_) {}, onTap: () {}));
}
void inertRuntimeCallbacks(dynamic callback) {
GestureDetector(onTapMove: callback);
f.GestureDetector(onTapMove: (_) {});
GestureDetector(onTapMove: callback, onTap: (null));
InkWell(onSecondaryTapCancel: () {});
InkResponse(onSecondaryTapCancel: (callback));
InkWell(onTapCancel: callback);
InkResponse(onTapCancel: () {});
InkWell(onTapCancel: callback, onSecondaryTapCancel: callback);
InkResponse(onTapCancel: callback, onSecondaryTapCancel: callback);
InkWell(onTapCancel: callback, onSecondaryTapCancel: callback,
onTap: null, onTapDown: null, onTapUp: null, onDoubleTap: null,
onLongPress: null, onLongPressUp: null,
onSecondaryTap: null, onSecondaryTapDown: (null), onSecondaryTapUp: null);
InkResponse(onTapCancel: callback, onSecondaryTapCancel: callback,
onTap: null, onTapDown: null, onTapUp: null, onDoubleTap: null,
onLongPress: null, onLongPressUp: null,
onSecondaryTap: null, onSecondaryTapDown: null, onSecondaryTapUp: (null));
}Configure accessible-widget-labels
Set its severity in falcon.json. See the configuration guide.
{
"linter": {
"rules": {
"a11y": {
"accessible-widget-labels": "error"
}
}
}
}Or silence one occurrence with a suppression comment; the reason is required.
// falcon-ignore lint/a11y/accessible-widget-labels: <reason>More accessibility rules
- avoid-missing-image-altflutter
Requires semanticLabel on Flutter Image and imageSemanticLabel on
FadeInImage. - minimum-touch-targetflutter
Warn about explicitly undersized Flutter touch targets.
- prefer-action-button-tooltipflutter
Requires useful tooltips on Flutter floating action buttons and icon buttons.