From 90aa5d2e2dc09d0e99dfe322527272e2aab87acb Mon Sep 17 00:00:00 2001 From: Deepak Kumar Bharti Date: Thu, 15 Oct 2026 12:27:31 +0530 Subject: [PATCH] [material_ui] Document how to programmatically clear DropdownMenu selection Improve documentation and add an interactive sample demonstrating how to programmatically clear or reset the selection in DropdownMenu using a TextEditingController alongside resetting the state variable. Fixes https://github.com/flutter/flutter/issues/177599 --- .../lib/dropdown_menu/dropdown_menu.3.dart | 95 +++++++++++++++++++ .../dropdown_menu/dropdown_menu.3_test.dart | 53 +++++++++++ .../material_ui/lib/src/dropdown_menu.dart | 62 +++++++++++- ...ge_2026_10_15_dropdown_menu_clear_doc.yaml | 3 + 4 files changed, 210 insertions(+), 3 deletions(-) create mode 100644 packages/material_ui/example/lib/dropdown_menu/dropdown_menu.3.dart create mode 100644 packages/material_ui/example/test/dropdown_menu/dropdown_menu.3_test.dart create mode 100644 packages/material_ui/pending_changelogs/change_2026_10_15_dropdown_menu_clear_doc.yaml diff --git a/packages/material_ui/example/lib/dropdown_menu/dropdown_menu.3.dart b/packages/material_ui/example/lib/dropdown_menu/dropdown_menu.3.dart new file mode 100644 index 000000000000..e19f96a2c9bc --- /dev/null +++ b/packages/material_ui/example/lib/dropdown_menu/dropdown_menu.3.dart @@ -0,0 +1,95 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// #region body +import 'package:material_ui/material_ui.dart'; + +/// Flutter code sample for [DropdownMenu] showing how to programmatically +/// clear or reset the selection using a [TextEditingController]. + +void main() => runApp(const DropdownMenuClearExampleApp()); + +class DropdownMenuClearExampleApp extends StatelessWidget { + const DropdownMenuClearExampleApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + home: Scaffold( + appBar: AppBar(title: const Text('Clear DropdownMenu Sample')), + body: const Center(child: DropdownMenuClearExample()), + ), + ); + } +} + +class DropdownMenuClearExample extends StatefulWidget { + const DropdownMenuClearExample({super.key}); + + @override + State createState() => + _DropdownMenuClearExampleState(); +} + +enum ColorItem { + red('Red'), + green('Green'), + blue('Blue'); + + const ColorItem(this.label); + final String label; +} + +class _DropdownMenuClearExampleState extends State { + final TextEditingController _controller = TextEditingController(); + ColorItem? _selectedColor; + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + void _clearSelection() { + setState(() { + _selectedColor = null; + _controller.clear(); + }); + } + + @override + Widget build(BuildContext context) { + return Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + DropdownMenu( + controller: _controller, + initialSelection: _selectedColor, + label: const Text('Color'), + onSelected: (ColorItem? color) { + setState(() { + _selectedColor = color; + }); + }, + dropdownMenuEntries: ColorItem.values + .map>((ColorItem color) { + return DropdownMenuEntry( + value: color, + label: color.label, + ); + }) + .toList(), + ), + const SizedBox(height: 20), + FilledButton( + onPressed: _clearSelection, + child: const Text('Clear selection'), + ), + const SizedBox(height: 20), + Text('Selected: ${_selectedColor?.label ?? 'None'}'), + ], + ); + } +} +// #endregion body diff --git a/packages/material_ui/example/test/dropdown_menu/dropdown_menu.3_test.dart b/packages/material_ui/example/test/dropdown_menu/dropdown_menu.3_test.dart new file mode 100644 index 000000000000..33f380abc921 --- /dev/null +++ b/packages/material_ui/example/test/dropdown_menu/dropdown_menu.3_test.dart @@ -0,0 +1,53 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_test/flutter_test.dart'; +import 'package:material_ui/material_ui.dart'; +import 'package:material_ui_examples/dropdown_menu/dropdown_menu.3.dart' + as example; + +void main() { + testWidgets('Selecting an entry updates the text field and state', ( + WidgetTester tester, + ) async { + await tester.pumpWidget(const example.DropdownMenuClearExampleApp()); + + expect(find.text('Selected: None'), findsOneWidget); + expect(find.widgetWithText(TextField, ''), findsOneWidget); + + // Open menu and select Green. + await tester.tap(find.byType(DropdownMenu)); + await tester.pumpAndSettle(); + + await tester.tap(find.widgetWithText(MenuItemButton, 'Green').last); + await tester.pumpAndSettle(); + + expect(find.text('Selected: Green'), findsOneWidget); + expect(find.widgetWithText(TextField, 'Green'), findsOneWidget); + }); + + testWidgets( + 'Pressing clear selection button resets the text field and state', + (WidgetTester tester) async { + await tester.pumpWidget(const example.DropdownMenuClearExampleApp()); + + // Open menu and select Blue. + await tester.tap(find.byType(DropdownMenu)); + await tester.pumpAndSettle(); + + await tester.tap(find.widgetWithText(MenuItemButton, 'Blue').last); + await tester.pumpAndSettle(); + + expect(find.text('Selected: Blue'), findsOneWidget); + expect(find.widgetWithText(TextField, 'Blue'), findsOneWidget); + + // Tap clear button. + await tester.tap(find.widgetWithText(FilledButton, 'Clear selection')); + await tester.pumpAndSettle(); + + expect(find.text('Selected: None'), findsOneWidget); + expect(find.widgetWithText(TextField, ''), findsOneWidget); + }, + ); +} diff --git a/packages/material_ui/lib/src/dropdown_menu.dart b/packages/material_ui/lib/src/dropdown_menu.dart index 4270397049f2..dbaca8ca7262 100644 --- a/packages/material_ui/lib/src/dropdown_menu.dart +++ b/packages/material_ui/lib/src/dropdown_menu.dart @@ -183,6 +183,19 @@ enum DropdownMenuCloseBehavior { /// /// /// +/// +/// +/// This sample demonstrates how to programmatically clear or reset the selection +/// in a [DropdownMenu] using a [TextEditingController]. +/// +// TODO(framework): Replace the following block with a @dartpad directive +// when it's supported. https://github.com/dart-lang/dartdoc/issues/4123 +/// {@macro material_ui.dartpad_guide} +/// +/// {@example /example/lib/dropdown_menu/dropdown_menu.3.dart#body} +/// +/// +/// /// See also: /// /// * [MenuAnchor], which is a widget used to mark the "anchor" for a set of submenus. @@ -448,6 +461,33 @@ class DropdownMenu extends StatefulWidget { /// Controls the text being edited or selected in the menu. /// /// If null, this widget will create its own [TextEditingController]. + /// + /// A [TextEditingController] can be provided to programmatically clear or modify + /// the displayed selection. For example, calling [TextEditingController.clear] + /// clears the text displayed in the dropdown menu. + /// + /// When tracking the selected value in a state variable, calling + /// [TextEditingController.clear] alongside updating the state variable to null + /// is required to clear the displayed selection, as updating [initialSelection] + /// does not clear the text field. + /// + /// + /// + /// This sample demonstrates how to programmatically clear the selection in a + /// [DropdownMenu] using a [TextEditingController]. + /// + // TODO(framework): Replace the following block with a @dartpad directive + // when it's supported. https://github.com/dart-lang/dartdoc/issues/4123 + /// {@macro material_ui.dartpad_guide} + /// + /// {@example /example/lib/dropdown_menu/dropdown_menu.3.dart#body} + /// + /// + /// + /// See also: + /// + /// * [initialSelection], which sets the initial selection when the widget is + /// first created. final TextEditingController? controller; /// The value used for an initial selection. @@ -456,13 +496,29 @@ class DropdownMenu extends StatefulWidget { /// is first created. If the value matches one of the [dropdownMenuEntries], /// the corresponding label will be displayed in the text field. /// - /// Setting this to null does not clear the text field. + /// Setting this to null does not clear the text field because [initialSelection] + /// only specifies an initial selection and does not act as a reactive, controlled + /// selection property. /// - /// To programmatically clear the text field, use a [TextEditingController] - /// and call [TextEditingController.clear] on it. + /// To programmatically clear or reset the selection, provide a [controller] + /// and call [TextEditingController.clear] on it alongside resetting the state + /// variable to null. /// /// Defaults to null. /// + /// + /// + /// This sample demonstrates how to programmatically clear the selection in a + /// [DropdownMenu] using a [TextEditingController]. + /// + // TODO(framework): Replace the following block with a @dartpad directive + // when it's supported. https://github.com/dart-lang/dartdoc/issues/4123 + /// {@macro material_ui.dartpad_guide} + /// + /// {@example /example/lib/dropdown_menu/dropdown_menu.3.dart#body} + /// + /// + /// /// See also: /// /// * [controller], which is required to programmatically clear or modify diff --git a/packages/material_ui/pending_changelogs/change_2026_10_15_dropdown_menu_clear_doc.yaml b/packages/material_ui/pending_changelogs/change_2026_10_15_dropdown_menu_clear_doc.yaml new file mode 100644 index 000000000000..1950e6aa9032 --- /dev/null +++ b/packages/material_ui/pending_changelogs/change_2026_10_15_dropdown_menu_clear_doc.yaml @@ -0,0 +1,3 @@ +changelog: | + - Clarifies how to programmatically clear or reset the selection in `DropdownMenu`. +version: patch