-
Notifications
You must be signed in to change notification settings - Fork 29.7k
Description
Use case
A DropdownMenu configured as a non-editable dropdown (select control) should not allow text input in its text field, regardless of how it receives focus. When focused, the component as a whole should be highlighted, allowing the user to open the menu with keyboard actions such as the Space or Enter key. This behavior would align with standard dropdown components, such as the Material Web select component.
Right now, it is not possible to have a non-editable dropdown and also provide a FocusNode.
To clarify, by non-editable dropdown I mean a dropdown that works like a normal select control without a text field, only a selector.
In many real situations we still need to use a FocusNode object, for example:
- When submitting the previous field and programmatically moving focus to the dropdown.
- When submitting a form and focusing the first invalid field, which might be the dropdown.
Example of current behavior:
Details
To create a DropdownMenu that functions as a simple, non-editable selector, the current approach involves setting requestFocusOnTap: false, enableSearch: false, and enableFilter: false. While this correctly prevents the text field from activating on a mouse click, it does not prevent keyboard input when the widget gains focus through other means.
In this example, pressing the button gives focus to the DropdownMenu, which incorrectly allows text input.
Flutter version:
stable : 3.35.7
master : 3.38.0-1.0.pre-407
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Container(
padding: const EdgeInsets.all(24.0),
alignment: Alignment.center,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 24,
children: [
OutlinedButton(
onPressed: () => focusNode.requestFocus(),
child: const Text('Focus DropdownMenu'),
),
DropdownMenu<Option>(
focusNode: focusNode,
requestFocusOnTap: false,
enableSearch: false,
enableFilter: false,
initialSelection: Option.a,
dropdownMenuEntries: Option.values
.map(
(option) =>
DropdownMenuEntry(value: option, label: option.name),
)
.toList(),
onSelected: (Option? option) =>
setState(() => selectedOption = option),
),
],
),
),
),
);
}
Option? selectedOption;
FocusNode focusNode = FocusNode();
@override
dispose() {
focusNode.dispose();
super.dispose();
}
}
enum Option { a, b }
Proposal
Proposal 1
If enableFilter is set to false and enableSearch is also set to false, the widget should behave like a select control without a text field, regardless of how focus is requested or whether a custom FocusNode is provided. It should not depend on requestFocusOnTap for that behavior.
The requestFocusOnTap parameter should be removed.
Keep in mind that if we choose this proposal, we must also consider another scenario that is currently not implemented:
When DropdownMenu is used as a select, it should focus/highlight the item that matches keyboard input even when there is no text field.
This matters because the current enableSearch setting disables highlight behavior when set to false, which could conflict with this new behavior if implemented in the future.
Example
Case 1
-
Open dropdown
-
Press "a" (Go to the first item that starts with "a")
-
Press "a" again (Go to the next item that starts with "a")
-
Press "a" again (Return to the first item that starts with "a" since there are no more matches)
Case 2
Proposal 2
Add another parameter to make the component work strictly as a select.
Possible names:
showSearch:boolsearchable:boolselectOnly:boolenableTextFieldSearch:boolmode:enum DropdownMenuMode {select, textField}
The requestFocusOnTap parameter should be removed.
In this case, make sure the current enableSearch does not cause confusion with this new parameter.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status
