Skip to content

Allow DropdownMenu to be non-editable and focusable (select control) #178009

@GiancarloCante

Description

@GiancarloCante

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:

  1. When submitting the previous field and programmatically moving focus to the dropdown.
  2. 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 }
Image

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

  1. Open dropdown

    Image
  2. Press "a" (Go to the first item that starts with "a")

    Image
  3. Press "a" again (Go to the next item that starts with "a")

    Image
  4. Press "a" again (Return to the first item that starts with "a" since there are no more matches)

    Image

Case 2

Image
  1. Quickly type a combination of keys like "a4" — this focuses the item that matches that prefix.
    In this case it jumps to a4 and skips a2 and a3.

    Image

Proposal 2

Add another parameter to make the component work strictly as a select.

Possible names:

  • showSearch: bool
  • searchable : bool
  • selectOnly: bool
  • enableTextFieldSearch: bool
  • mode: 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

P3Issues that are less important to the Flutter projecta: text inputEntering text in a text field or keyboard related problemsc: new featureNothing broken; request for a new capabilityc: proposalA detailed proposal for a change to Flutterf: focusFocus traversal, gaining or losing focusf: material designflutter/packages/flutter/material repository.frameworkflutter/packages/flutter repository. See also f: labels.r: fixedIssue is closed as already fixed in a newer versionteam-designOwned by Design Languages teamtriaged-designTriaged by Design Languages team

Type

No type

Projects

Status

Done (PR merged)

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions