accessible-widget-labels

Path
lint/a11y/accessible-widget-labels
Default
Off, opt in
Origin
Falcon
Domain
flutter
Rule
1 of 512
flutter

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

example.dartdart
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);
}
Provide an accessible label for this interactive widget.
4void actions() {
5 GestureDetector(onTap: () {});
Provide an accessible label for this interactive widget.
5 GestureDetector(onTap: () {});
6 f.InkWell(onTap: () {}, child: Icon(null));
Provide an accessible label for this interactive widget.
6 f.InkWell(onTap: () {}, child: Icon(null));
7 InkResponse(onTap: () {}, child: Text(' '));
Provide an accessible label for this interactive widget.
7 InkResponse(onTap: () {}, child: Text(' '));
8 GestureDetector(onTap: () {}, child: Icon(null));
Provide an accessible label for this interactive widget.
8 GestureDetector(onTap: () {}, child: Icon(null));
9 InkWell(onTap: () {}, child: Text(''));
Provide an accessible label for this interactive widget.
9 InkWell(onTap: () {}, child: Text(''));
10 InkResponse(onTap: () {});
Provide an accessible label for this interactive widget.
10 InkResponse(onTap: () {});
11 Tooltip(message: '', child: InkWell(onTap: () {}));
Provide an accessible label for this interactive widget.
11 Tooltip(message: '', child: InkWell(onTap: () {}));
12 Tooltip(richMessage: null, child: InkWell(onTap: () {}));
Provide an accessible label for this interactive widget.
12 Tooltip(richMessage: null, child: InkWell(onTap: () {}));
13 Tooltip(richMessage: (null), child: InkResponse(onTap: () {}));
Provide an accessible label for this interactive widget.
13 Tooltip(richMessage: (null), child: InkResponse(onTap: () {}));
14 Semantics(attributedLabel: null, child: InkWell(onTap: () {}));
Provide an accessible label for this interactive widget.
14 Semantics(attributedLabel: null, child: InkWell(onTap: () {}));
15 Semantics(attributedLabel: (null), child: InkResponse(onTap: () {}));
Provide an accessible label for this interactive widget.
18void shadowed(dynamic Tooltip, dynamic Semantics) {
19 Tooltip(richMessage: 'Delete', child: InkWell(onTap: () {}));
Provide an accessible label for this interactive widget.
19 Tooltip(richMessage: 'Delete', child: InkWell(onTap: () {}));
20 Semantics(attributedLabel: 'Delete', child: InkResponse(onTap: () {}));
Provide an accessible label for this interactive widget.
24 Tooltip(richMessage: richMessage, child: InkWell(onTap: () {}));
25 InkWell(onTap: () {});
Provide an accessible label for this interactive widget.
26 Semantics(attributedLabel: attributedLabel, child: InkResponse(onTap: () {}));
27 InkResponse(onTap: () {});
Provide an accessible label for this interactive widget.
30void additionalGestures(dynamic callback) {
31 GestureDetector(onSecondaryTapCancel: callback);
Provide an accessible label for this interactive widget.
31 GestureDetector(onSecondaryTapCancel: callback);
32 GestureDetector(onTertiaryTapCancel: callback);
Provide an accessible label for this interactive widget.
32 GestureDetector(onTertiaryTapCancel: callback);
33 GestureDetector(onLongPressCancel: callback);
Provide an accessible label for this interactive widget.
33 GestureDetector(onLongPressCancel: callback);
34 GestureDetector(onSecondaryLongPressDown: callback);
Provide an accessible label for this interactive widget.
34 GestureDetector(onSecondaryLongPressDown: callback);
35 GestureDetector(onSecondaryLongPressCancel: callback);
Provide an accessible label for this interactive widget.
35 GestureDetector(onSecondaryLongPressCancel: callback);
36 GestureDetector(onSecondaryLongPress: callback);
Provide an accessible label for this interactive widget.
36 GestureDetector(onSecondaryLongPress: callback);
37 GestureDetector(onSecondaryLongPressStart: callback);
Provide an accessible label for this interactive widget.
37 GestureDetector(onSecondaryLongPressStart: callback);
38 GestureDetector(onSecondaryLongPressMoveUpdate: callback);
Provide an accessible label for this interactive widget.
38 GestureDetector(onSecondaryLongPressMoveUpdate: callback);
39 GestureDetector(onSecondaryLongPressUp: callback);
Provide an accessible label for this interactive widget.
39 GestureDetector(onSecondaryLongPressUp: callback);
40 GestureDetector(onSecondaryLongPressEnd: callback);
Provide an accessible label for this interactive widget.
40 GestureDetector(onSecondaryLongPressEnd: callback);
41 GestureDetector(onTertiaryLongPressDown: callback);
Provide an accessible label for this interactive widget.
41 GestureDetector(onTertiaryLongPressDown: callback);
42 GestureDetector(onTertiaryLongPressCancel: callback);
Provide an accessible label for this interactive widget.
42 GestureDetector(onTertiaryLongPressCancel: callback);
43 GestureDetector(onTertiaryLongPress: callback);
Provide an accessible label for this interactive widget.
43 GestureDetector(onTertiaryLongPress: callback);
44 GestureDetector(onTertiaryLongPressStart: callback);
Provide an accessible label for this interactive widget.
44 GestureDetector(onTertiaryLongPressStart: callback);
45 GestureDetector(onTertiaryLongPressMoveUpdate: callback);
Provide an accessible label for this interactive widget.
45 GestureDetector(onTertiaryLongPressMoveUpdate: callback);
46 GestureDetector(onTertiaryLongPressUp: callback);
Provide an accessible label for this interactive widget.
46 GestureDetector(onTertiaryLongPressUp: callback);
47 GestureDetector(onTertiaryLongPressEnd: callback);
Provide an accessible label for this interactive widget.
47 GestureDetector(onTertiaryLongPressEnd: callback);
48 GestureDetector(onVerticalDragDown: callback);
Provide an accessible label for this interactive widget.
48 GestureDetector(onVerticalDragDown: callback);
49 GestureDetector(onVerticalDragCancel: callback);
Provide an accessible label for this interactive widget.
49 GestureDetector(onVerticalDragCancel: callback);
50 GestureDetector(onHorizontalDragDown: callback);
Provide an accessible label for this interactive widget.
50 GestureDetector(onHorizontalDragDown: callback);
51 GestureDetector(onHorizontalDragCancel: callback);
Provide an accessible label for this interactive widget.
51 GestureDetector(onHorizontalDragCancel: callback);
52 GestureDetector(onForcePressStart: callback);
Provide an accessible label for this interactive widget.
52 GestureDetector(onForcePressStart: callback);
53 GestureDetector(onForcePressPeak: callback);
Provide an accessible label for this interactive widget.
53 GestureDetector(onForcePressPeak: callback);
54 GestureDetector(onForcePressUpdate: callback);
Provide an accessible label for this interactive widget.
54 GestureDetector(onForcePressUpdate: callback);
55 GestureDetector(onForcePressEnd: callback);
Provide an accessible label for this interactive widget.
55 GestureDetector(onForcePressEnd: callback);
56 GestureDetector(onPanCancel: callback);
Provide an accessible label for this interactive widget.
56 GestureDetector(onPanCancel: callback);
57 f.GestureDetector(onTapMove: (_) {}, onTap: callback);
Provide an accessible label for this interactive widget.
57 f.GestureDetector(onTapMove: (_) {}, onTap: callback);
58 GestureDetector(onSecondaryLongPress: () {});
Provide an accessible label for this interactive widget.
58 GestureDetector(onSecondaryLongPress: () {});
59 InkWell(onSecondaryTapCancel: () {}, onSecondaryTapDown: callback);
Provide an accessible label for this interactive widget.
59 InkWell(onSecondaryTapCancel: () {}, onSecondaryTapDown: callback);
60 InkResponse(onSecondaryTapCancel: (callback), onSecondaryTap: () {});
Provide an accessible label for this interactive widget.
63void inkEnablingCallbacks(dynamic callback) {
64 InkWell(onTap: callback);
Provide an accessible label for this interactive widget.
64 InkWell(onTap: callback);
65 InkWell(onTapDown: callback);
Provide an accessible label for this interactive widget.
65 InkWell(onTapDown: callback);
66 InkWell(onTapUp: callback);
Provide an accessible label for this interactive widget.
66 InkWell(onTapUp: callback);
67 InkWell(onDoubleTap: callback);
Provide an accessible label for this interactive widget.
67 InkWell(onDoubleTap: callback);
68 InkWell(onLongPress: callback);
Provide an accessible label for this interactive widget.
68 InkWell(onLongPress: callback);
69 InkWell(onLongPressUp: callback);
Provide an accessible label for this interactive widget.
69 InkWell(onLongPressUp: callback);
70 InkWell(onSecondaryTap: callback);
Provide an accessible label for this interactive widget.
70 InkWell(onSecondaryTap: callback);
71 InkWell(onSecondaryTapDown: callback);
Provide an accessible label for this interactive widget.
71 InkWell(onSecondaryTapDown: callback);
72 InkWell(onSecondaryTapUp: callback);
Provide an accessible label for this interactive widget.
72 InkWell(onSecondaryTapUp: callback);
73 InkResponse(onTap: callback);
Provide an accessible label for this interactive widget.
73 InkResponse(onTap: callback);
74 InkResponse(onTapDown: callback);
Provide an accessible label for this interactive widget.
74 InkResponse(onTapDown: callback);
75 InkResponse(onTapUp: callback);
Provide an accessible label for this interactive widget.
75 InkResponse(onTapUp: callback);
76 InkResponse(onDoubleTap: callback);
Provide an accessible label for this interactive widget.
76 InkResponse(onDoubleTap: callback);
77 InkResponse(onLongPress: callback);
Provide an accessible label for this interactive widget.
77 InkResponse(onLongPress: callback);
78 InkResponse(onLongPressUp: callback);
Provide an accessible label for this interactive widget.
78 InkResponse(onLongPressUp: callback);
79 InkResponse(onSecondaryTap: callback);
Provide an accessible label for this interactive widget.
79 InkResponse(onSecondaryTap: callback);
80 InkResponse(onSecondaryTapDown: callback);
Provide an accessible label for this interactive widget.
80 InkResponse(onSecondaryTapDown: callback);
81 InkResponse(onSecondaryTapUp: callback);
Provide an accessible label for this interactive widget.
81 InkResponse(onSecondaryTapUp: callback);
82 GestureDetector(onTapCancel: callback);
Provide an accessible label for this interactive widget.
82 GestureDetector(onTapCancel: callback);
83 InkWell(onTapCancel: callback, onTap: () {});
Provide an accessible label for this interactive widget.
83 InkWell(onTapCancel: callback, onTap: () {});
84 InkResponse(onTapCancel: () {}, onTapUp: callback);

Valid

example.dartdart
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.

falcon.jsonjson
{
  "linter": {
    "rules": {
      "a11y": {
        "accessible-widget-labels": "error"
      }
    }
  }
}

Or silence one occurrence with a suppression comment; the reason is required.

example.dartdart
// falcon-ignore lint/a11y/accessible-widget-labels: <reason>