Skip to content

Conversation

@LauYewHang
Copy link

@LauYewHang LauYewHang commented Sep 18, 2025

This PR adds new properties to DropdownMenu class that allows padding customization for its leadingIcon and trailingIcon, as well as customization on how the trailing icon button in a DropdownMenu should be constructed. This changes hope to address the issue where a DropdownMenu's minimum size (specifically the height) is affected by the trailing IconButton within it. In which due to the constraints of the IconButton having a minimum size of 48x48 under M3 design guidelines, the DropdownMenu's height is unable to go lower than this value.

Comparison
Before changes:

Code:

DropdownMenu<IconLabel>(
  dropdownMenuEntries: IconLabel.entries,
  requestFocusOnTap: true,
  inputDecorationTheme: InputDecorationTheme(
    border: OutlineInputBorder(),
    suffixIconConstraints: BoxConstraints(),
    suffixIconColor: Color(0xFF00FFFF),
    isDense: true,
    contentPadding: EdgeInsets.zero,
  ),
  trailingIcon: Icon(Icons.favorite),
)
After changes:

Code:

DropdownMenu<IconLabel>(
  dropdownMenuEntries: IconLabel.entries,
  requestFocusOnTap: true,
  inputDecorationTheme: InputDecorationTheme(
    border: OutlineInputBorder(),
    suffixIconConstraints: BoxConstraints(),
    suffixIconColor: Color(0xFF00FFFF),
    isDense: true,
    contentPadding: EdgeInsets.zero,
  ),
  trailingIcon: Icon(Icons.favorite),
  trailingIconPadding: EdgeInsets.zero,
  trailingIconButtonStyle: DropDownMenuTrailingIconButtonStyle(
    iconSize: 12,
    padding: EdgeInsets.zero,
    style: ButtonStyle(
      tapTargetSize: MaterialTapTargetSize.shrinkWrap
    )
  ),
)

Fixes #135903

Pre-launch Checklist

  • I read the [Contributor Guide] and followed the process outlined there for submitting PRs.
  • I read the [Tree Hygiene] wiki page, which explains my responsibilities.
  • I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement].
  • I signed the [CLA].
  • I listed at least one issue that this PR fixes in the description above.
  • I updated/added relevant documentation (doc comments with ///).
  • I added new tests to check the change I am making, or this PR is [test-exempt].
  • I followed the [breaking change policy] and added [Data Driven Fixes] where supported.
  • All existing and new tests are passing.

…g icon and trailing icon. Add DropDownMenuTrailingIconButtonStyle class that allows customization on how the trailing IconButton in a DropdownMenu menu should be constructed.
…n how its trailing IconButton is being constructed.
…adding of property trailingIconPadding. If trailingIconPadding is null, the padding will depends on inputDecorationTheme.isCollapsed.
@github-actions github-actions bot added framework flutter/packages/flutter repository. See also f: labels. f: material design flutter/packages/flutter/material repository. d: api docs Issues with https://api.flutter.dev/ d: examples Sample code and demos labels Sep 18, 2025
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces new properties to the DropdownMenu widget to allow for more customization of the leading and trailing icons, specifically their padding and the style of the trailing icon button. This is a valuable addition that addresses a known issue with the minimum height of the DropdownMenu. The changes include a new DropDownMenuTrailingIconButtonStyle class, updates to the DropdownMenu widget, and a new example with tests.

My review focuses on some naming conventions and typos in the new API and documentation to improve clarity and consistency with the rest of the Flutter framework. These are important to address before merging as they affect the public API.

@LauYewHang
Copy link
Author

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces new properties to the DropdownMenu widget to allow for more detailed customization of the leading and trailing icons. Specifically, it adds leadingIconPadding, trailingIconPadding, and trailingIconButtonStyle. The trailingIconButtonStyle uses a new helper class, DropdownMenuTrailingIconButtonStyle, to configure the underlying IconButton for the trailing icon. This change effectively addresses the issue of the DropdownMenu's minimum height being dictated by the default IconButton size. The changes include new API documentation, an example, and a corresponding test.

My review has identified a couple of areas for improvement in the documentation to enhance clarity for developers. I've left specific comments on those.

@LauYewHang
Copy link
Author

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds leadingIconPadding, trailingIconPadding, and trailingIconButtonStyle properties to the DropdownMenu widget. These changes allow for customization of the padding and style of the leading and trailing icons. A new DropdownMenuTrailingIconButtonStyle class is introduced to configure the trailing icon button. An example and a corresponding test for the new functionality have also been added. My feedback includes suggestions to improve documentation clarity and code style.

Copy link
Contributor

@QuncCccccc QuncCccccc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for your contribution! We should add unit tests for any new properties we add in dropdown_menu_test.dart.

/// This sample demonstrates how the [trailingIconButtonStyle] property allows customization on the construction of trailing icon button.
/// ** See code in examples/api/lib/material/dropdown_menu/dropdown_menu.customize_trailing_icon_button.0.dart **
/// {@end-tool}
final DropdownMenuTrailingIconButtonStyle? trailingIconButtonStyle;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the new DropdownMenuTrailingIconButtonStyle class is necessary for fixing the issue linked. xxxTheme can be used for widget customization, such as IconButtonTheme, but I don't think it's necessary here as well.

/// it is an extra layer of padding between leading icon widget and the text input field.
///
/// Defaults to EdgeInsets.all(8.0).
final EdgeInsetsGeometry? leadingIconPadding;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of adding new APIs that only change the leading and trailing icon paddings. I think maybe we should add "trailingButton" and "leadingButton" so we can set something like:

final Widget trailingButton = widget.showTrailingIcon
            ? **widget.trailingButton** ?? Padding(...)
            :  ...

Similar for leading button. I think maybe this can be better for leading and trailing button customization. The existing trailingIcon and leadingIcon look a bit confusing and limit the customizability. We can consider to deprecate them.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI, this is something I'm currently working on in the context of #174096 and #175847 (it will also help for other issues).

@@ -0,0 +1,44 @@
// Copyright 2014 The Flutter Authors. All rights reserved.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this example looks relatively simple, so I think maybe it's not necessary.

@Gustl22
Copy link
Contributor

Gustl22 commented Sep 26, 2025

I also think, we should have a more general approach for customization, like in #175847 as @bleroux already mentioned.

@dkwingsmt
Copy link
Contributor

Yeah. It seems to me that #176264 can achieve what this PR wants to do, although in a more complicated style.
@bleroux Is it so?
@LauYewHang Would you accept that?

@bleroux
Copy link
Contributor

bleroux commented Oct 7, 2025

Yes, #176264 is a more general approach to fix DropdownMenu lack of customizability.

@LauYewHang
Copy link
Author

@dkwingsmt Yes I accept that #176264 by @bleroux provides a better solution to achieve what this PR intentional to do and I will be closing this PR. Thanks for the help~

@LauYewHang LauYewHang closed this Oct 8, 2025
github-merge-queue bot pushed a commit that referenced this pull request Oct 20, 2025
## Description

This PR adds `DropdownMenu.decorationBuilder`.
The goal is to make `DropdownMenu` more flexible.

Before this PR, several fields are used by `DropdownMenu` to create an
inner `InputDecoration`. This approach has several limitations:
- `InputDecoration` has more fields that the ones that are exposed
- `DropdownMenu` makes some choices that can't be change. Especially, it
creates an IconButton (with hardcoded padding) which is passed to
`InputDecoration.suffixIcon`. This inner `IconButton` introduces some
difficulty related to focus management and UI customization.

The new `DropdownMenu.decorationBuilder` property offers users a way to
take control on the inner `InputDecoration` in a non-breaking way.

In a future PR, this property will help replacing the default
`IconButton`.
Currently users can replace the `IconButton` using this code sample:

<details><summary>DropdownMenu without IconButton</summary>

```dart
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  MyApp({super.key});

  final List<DropdownMenuEntry<String>> menuEntries = [
    "Red",
    "Green",
    "Blue",
  ].map((t) => DropdownMenuEntry<String>(label: t, value: t)).toList();

  @OverRide
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: SizedBox(
            width: 220,
            child: DropdownMenu<String>(
              expandedInsets: EdgeInsets.zero,
              requestFocusOnTap: true,
              dropdownMenuEntries: menuEntries,
              decorationBuilder: (context, controller) {
                return InputDecoration(
                  labelText: 'Label text',
                  helperText: 'Select a color or enter one',
                  suffixIcon: controller.isOpen
                      ? const Icon(Icons.arrow_drop_up)
                      : const Icon(Icons.arrow_drop_down),
                );
              },
            ),
          ),
        ),
      ),
    );
  }
}
``` 

</details> 

## Related Issue

Fixes [DropDownMenu secondary trailing
widget](#175847)
Will help for [Make DropdownMenu's trailing icon not focusable by
default](#174096)

## Related discussions

#175847 (comment)
#175558 (comment)

## Tests

- Adds 7 tests.
reidbaker pushed a commit to AbdeMohlbi/flutter that referenced this pull request Dec 10, 2025
## Description

This PR adds `DropdownMenu.decorationBuilder`.
The goal is to make `DropdownMenu` more flexible.

Before this PR, several fields are used by `DropdownMenu` to create an
inner `InputDecoration`. This approach has several limitations:
- `InputDecoration` has more fields that the ones that are exposed
- `DropdownMenu` makes some choices that can't be change. Especially, it
creates an IconButton (with hardcoded padding) which is passed to
`InputDecoration.suffixIcon`. This inner `IconButton` introduces some
difficulty related to focus management and UI customization.

The new `DropdownMenu.decorationBuilder` property offers users a way to
take control on the inner `InputDecoration` in a non-breaking way.

In a future PR, this property will help replacing the default
`IconButton`.
Currently users can replace the `IconButton` using this code sample:

<details><summary>DropdownMenu without IconButton</summary>

```dart
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  MyApp({super.key});

  final List<DropdownMenuEntry<String>> menuEntries = [
    "Red",
    "Green",
    "Blue",
  ].map((t) => DropdownMenuEntry<String>(label: t, value: t)).toList();

  @OverRide
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: SizedBox(
            width: 220,
            child: DropdownMenu<String>(
              expandedInsets: EdgeInsets.zero,
              requestFocusOnTap: true,
              dropdownMenuEntries: menuEntries,
              decorationBuilder: (context, controller) {
                return InputDecoration(
                  labelText: 'Label text',
                  helperText: 'Select a color or enter one',
                  suffixIcon: controller.isOpen
                      ? const Icon(Icons.arrow_drop_up)
                      : const Icon(Icons.arrow_drop_down),
                );
              },
            ),
          ),
        ),
      ),
    );
  }
}
``` 

</details> 

## Related Issue

Fixes [DropDownMenu secondary trailing
widget](flutter#175847)
Will help for [Make DropdownMenu's trailing icon not focusable by
default](flutter#174096)

## Related discussions

flutter#175847 (comment)
flutter#175558 (comment)

## Tests

- Adds 7 tests.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

d: api docs Issues with https://api.flutter.dev/ d: examples Sample code and demos f: material design flutter/packages/flutter/material repository. framework flutter/packages/flutter repository. See also f: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Optional padding for DropdownMenu's leadingIcon and trailingIcon

5 participants