Skip to content

Commit e706d7d

Browse files
authored
feat: Add autofocus for MenuItemButton (#139396)
MenuAnchor for Material 3 is great for contextual menus but there are some minor issues related to accessibility. This PR aims to close the gap by adding `autofocus` to the menu item button so keyboard navigation is more intuitive. Otherwise, it becomes a mess to navigate through just keyboards. Partially resolves #139395 ## Additional Notes I should mention, I have not written tests for this due to it's trivial nature. I also lack the experience of writing Flutter tests in general, so if someone feels inclined to take over this PR and add it they're welcome to.
1 parent def5a38 commit e706d7d

File tree

2 files changed

+44
-0
lines changed

2 files changed

+44
-0
lines changed

packages/flutter/lib/src/material/menu_anchor.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -856,6 +856,7 @@ class MenuItemButton extends StatefulWidget {
856856
this.requestFocusOnHover = true,
857857
this.onFocusChange,
858858
this.focusNode,
859+
this.autofocus = false,
859860
this.shortcut,
860861
this.semanticsLabel,
861862
this.style,
@@ -897,6 +898,9 @@ class MenuItemButton extends StatefulWidget {
897898
/// {@macro flutter.widgets.Focus.focusNode}
898899
final FocusNode? focusNode;
899900

901+
/// {@macro flutter.widgets.Focus.autofocus}
902+
final bool autofocus;
903+
900904
/// The optional shortcut that selects this [MenuItemButton].
901905
///
902906
/// {@macro flutter.material.MenuBar.shortcuts_note}
@@ -1140,6 +1144,7 @@ class _MenuItemButtonState extends State<MenuItemButton> {
11401144
onFocusChange: widget.enabled ? widget.onFocusChange : null,
11411145
focusNode: _focusNode,
11421146
style: mergedStyle,
1147+
autofocus: widget.enabled && widget.autofocus,
11431148
statesController: widget.statesController,
11441149
clipBehavior: widget.clipBehavior,
11451150
isSemanticButton: null,

packages/flutter/test/material/menu_anchor_test.dart

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2229,6 +2229,45 @@ void main() {
22292229
expect(find.text('leadingIcon'), findsOneWidget);
22302230
});
22312231

2232+
testWidgets('autofocus is used when set and widget is enabled',
2233+
(WidgetTester tester) async {
2234+
2235+
listenForFocusChanges();
2236+
2237+
await tester.pumpWidget(
2238+
MaterialApp(
2239+
home: Material(
2240+
child: Column(
2241+
children: <Widget>[
2242+
MenuAnchor(
2243+
controller: controller,
2244+
menuChildren: <Widget>[
2245+
MenuItemButton(
2246+
autofocus: true,
2247+
// Required for clickability.
2248+
onPressed: () {},
2249+
child: Text(TestMenu.mainMenu0.label),
2250+
),
2251+
MenuItemButton(
2252+
onPressed: () {},
2253+
child: Text(TestMenu.mainMenu1.label),
2254+
),
2255+
],
2256+
),
2257+
const Expanded(child: Placeholder()),
2258+
],
2259+
),
2260+
),
2261+
),
2262+
);
2263+
2264+
controller.open();
2265+
await tester.pump();
2266+
2267+
expect(controller.isOpen, equals(true));
2268+
expect(focusedMenu, equals('MenuItemButton(Text("${TestMenu.mainMenu0.label}"))'));
2269+
});
2270+
22322271
testWidgets('trailingIcon is used when set', (WidgetTester tester) async {
22332272
await tester.pumpWidget(
22342273
MaterialApp(

0 commit comments

Comments
 (0)