Skip to content

Conversation

@bleroux
Copy link
Contributor

@bleroux bleroux commented Nov 20, 2025

Description

This PR adds logic to resolve DropdownMenuEntry.style properties with the correct WidgetState when an item is highlighted.

When MenuItemButton are highlighted the focused state is not added automatically because the focus does not move to the items (it stays on the TextField in order to let the user enters text to filter the items list). This PR sets the MenuItemButton.statesController with a forced focused state to let MenuItemButton know that the focused state should be use to resolve the properties.

Related Issue

Fixes DropdownMenuEntry style's text style is not resolving with states

Tests

  • Adds 1 tests.

@github-actions github-actions bot added framework flutter/packages/flutter repository. See also f: labels. f: material design flutter/packages/flutter/material repository. labels Nov 20, 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 correctly fixes an issue where DropdownMenuEntry.style properties were not being resolved for highlighted items. The approach of using a WidgetStatesController to force the :focus state is sound, and the added regression test effectively validates the fix for textStyle. I have two main points of feedback on the implementation in dropdown_menu.dart. First, the lifecycle management of the new _highlightedItemStatesController can be improved for better performance by creating it once in initState. Second, there's a pre-existing bug in how focused styles are applied that discards other state-dependent styles (like :hover), which I've provided a suggestion to fix.

Comment on lines +882 to +941
_highlightedItemStatesController?.dispose();
_highlightedItemStatesController = WidgetStatesController(<WidgetState>{
WidgetState.focused,
});
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

Creating and disposing a WidgetStatesController within the build method is inefficient and an anti-pattern. This leads to unnecessary object creation and disposal on every rebuild.

A better approach is to manage the controller's lifecycle within the State object. You can create a single, final _highlightedItemStatesController instance for the _DropdownMenuState, initialize it once, and dispose of it in the dispose method. This single instance can then be reused for any highlighted item.

This would involve:

  1. Changing the declaration in _DropdownMenuState to:
    final WidgetStatesController _highlightedItemStatesController =
        WidgetStatesController(<WidgetState>{WidgetState.focused});
  2. Updating dispose() to call _highlightedItemStatesController.dispose(); instead of _highlightedItemStatesController?.dispose();.
  3. Removing these lines that create and dispose the controller inside _buildButtons.

Comment on lines +882 to +941
_highlightedItemStatesController?.dispose();
_highlightedItemStatesController = WidgetStatesController(<WidgetState>{
WidgetState.focused,
});
Copy link
Contributor Author

@bleroux bleroux Nov 20, 2025

Choose a reason for hiding this comment

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

I opted for the creation of a new states controller each time because I don't think WidgetStatesController are supposed to be reused across several widgets (as they have listeners and a list of states which is updated by InkWell).
For instance, each InkWell (inside each MenuItemButton) will create a Focus widget with an onFocusChange callback that might remove the focused state. If the states controller is shared and this callback is called once then the controller will no more have the focus state turned on. Currently there is an ExcludeFocus widget surrongind each MenuItemButton, so this might not happen but it seems to me that reusing states controller for different widgets can lead to subtle issues.

@justinmc Maybe I'm too cautious here? Let me know if you encountered something similar.

Copy link
Contributor

Choose a reason for hiding this comment

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

By "reusing it for different widgets" you just mean for each MenuItemButton that is created each time this method is called?

In the docs for statesController I see:

  /// Classes based on this one can provide their own
  /// [WidgetStatesController] to which they've added listeners.
  /// They can also update the controller's [WidgetStatesController.value]
  /// however, this may only be done when it's safe to call
  /// [State.setState], like in an event handler.

It's not safe to call setState in the build phase, so I think you wouldn't be able to set the value back to focused here. So I think you are right, and you have to do it the way that you've done it here.

@bleroux bleroux requested a review from justinmc November 20, 2025 16:27
@bleroux bleroux force-pushed the fix_DropdownMenuEntry_styles_not_resolving branch 2 times, most recently from 946b2b9 to f5c7fd8 Compare November 28, 2025 09:28
@bleroux bleroux force-pushed the fix_DropdownMenuEntry_styles_not_resolving branch 2 times, most recently from 38582aa to 2ab74a8 Compare December 13, 2025 08:18
Copy link
Contributor

@justinmc justinmc left a comment

Choose a reason for hiding this comment

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

LGTM 👍 . I can't think of a better way to do the WidgetStatesController than what you've done, but if you have any other ideas let me know.

Comment on lines +923 to +938
if (entryIsSelected) {
_highlightedItemStatesController?.dispose();
Copy link
Contributor

Choose a reason for hiding this comment

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

Even if the entry is not selected should you still dispose _highlightedItemStatesController and set it to null?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Even if the entry is not selected should you still dispose _highlightedItemStatesController and set it to null?

It will be set to null and disposed in two cases:

  • when another entry is selected.
  • when the DropdownMenu will be disposed.

I think it's ok as either there is one entry selected and the controller will be properly destroyed or there is none and the controller will be destroyed when the DropdownMenu is (this second case seems similar to usual states controllers which have the same life time than the widget they are attached to).

Comment on lines +882 to +941
_highlightedItemStatesController?.dispose();
_highlightedItemStatesController = WidgetStatesController(<WidgetState>{
WidgetState.focused,
});
Copy link
Contributor

Choose a reason for hiding this comment

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

By "reusing it for different widgets" you just mean for each MenuItemButton that is created each time this method is called?

In the docs for statesController I see:

  /// Classes based on this one can provide their own
  /// [WidgetStatesController] to which they've added listeners.
  /// They can also update the controller's [WidgetStatesController.value]
  /// however, this may only be done when it's safe to call
  /// [State.setState], like in an event handler.

It's not safe to call setState in the build phase, so I think you wouldn't be able to set the value back to focused here. So I think you are right, and you have to do it the way that you've done it here.

@bleroux bleroux force-pushed the fix_DropdownMenuEntry_styles_not_resolving branch from 2ab74a8 to e0c2f37 Compare January 7, 2026 06:52
@bleroux bleroux added the autosubmit Merge PR when tree becomes green via auto submit App label Jan 7, 2026
@auto-submit auto-submit bot added this pull request to the merge queue Jan 7, 2026
Merged via the queue into flutter:master with commit 7d9198a Jan 7, 2026
71 checks passed
@flutter-dashboard flutter-dashboard bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Jan 7, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jan 7, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jan 7, 2026
@bleroux bleroux deleted the fix_DropdownMenuEntry_styles_not_resolving branch January 7, 2026 16:16
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jan 7, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jan 7, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jan 7, 2026
auto-submit bot pushed a commit to flutter/packages that referenced this pull request Jan 7, 2026
Roll Flutter from 13b2b91 to 01d37bc (74 revisions)

flutter/flutter@13b2b91...01d37bc

2026-01-07 stuartmorgan@google.com Replace Hybrid Composition wiki page with dev-facing content (flutter/flutter#180642)
2026-01-07 116356835+AbdeMohlbi@users.noreply.github.com Improve code quality in `FlutterActivityTest.java` (flutter/flutter#180585)
2026-01-07 iinozemtsev@google.com Roll Dart SDK to 3.11.0-296.1.beta (flutter/flutter#180633)
2026-01-07 vegorov@google.com Bump target Windows version to 10 (flutter/flutter#180624)
2026-01-07 goderbauer@google.com Run hook_user_defines and link_hook integration tests on CI (flutter/flutter#180622)
2026-01-07 iliyazelenkog@gmail.com Fix division by zero in RenderTable intrinsic size methods (flutter/flutter#178217)
2026-01-07 116356835+AbdeMohlbi@users.noreply.github.com Remove more  `requires 24` anotations (flutter/flutter#180116)
2026-01-07 engine-flutter-autoroll@skia.org Roll Skia from 3971dbb85d45 to c5359a4d720e (1 revision) (flutter/flutter#180631)
2026-01-07 huy@nevercode.io Fix TabBar.image does not render at initialIndex for the first time (flutter/flutter#179616)
2026-01-07 engine-flutter-autoroll@skia.org Roll Skia from 1e7ad625f6f7 to 3971dbb85d45 (3 revisions) (flutter/flutter#180627)
2026-01-07 goderbauer@google.com Unpin DDS (flutter/flutter#180571)
2026-01-07 bruno.leroux@gmail.com Fix DropdownMenuEntry.style not resolved when entry is highlighted (flutter/flutter#178873)
2026-01-07 116356835+AbdeMohlbi@users.noreply.github.com Remove unnecessary `@RequiresApi24` annotations from FlutterFragment methods (flutter/flutter#180117)
2026-01-07 engine-flutter-autoroll@skia.org Roll Skia from 7fc63228056b to 1e7ad625f6f7 (1 revision) (flutter/flutter#180616)
2026-01-07 engine-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from QfR2ZFZ5kGTD3raO3... to dTvN_JVSCfGFRasvH... (flutter/flutter#180612)
2026-01-07 bkonyi@google.com [ Widget Preview ] Add support for `dart:ffi` imports (flutter/flutter#180586)
2026-01-07 engine-flutter-autoroll@skia.org Roll Skia from eec90000a899 to 7fc63228056b (2 revisions) (flutter/flutter#180608)
2026-01-07 ulisses.hen@hotmail.com Add --web-define flag for template variable injection in Flutter web builds (flutter/flutter#175805)
2026-01-07 codefu@google.com docs(engine): update rbe notes (flutter/flutter#180599)
2026-01-06 engine-flutter-autoroll@skia.org Roll Skia from b6249496c230 to eec90000a899 (3 revisions) (flutter/flutter#180602)
2026-01-06 146823759+brahim-guaali@users.noreply.github.com Forward proxy 404 responses to client (flutter/flutter#179858)
2026-01-06 engine-flutter-autoroll@skia.org Roll Dart SDK from 40a8c6188f7f to d2e3ce177270 (1 revision) (flutter/flutter#180598)
2026-01-06 104009581+Saqib198@users.noreply.github.com Restore CLI precedence for web headers and HTTPS over web_dev_config.yaml (flutter/flutter#179639)
2026-01-06 engine-flutter-autoroll@skia.org Roll Skia from f5d9da13d56d to b6249496c230 (1 revision) (flutter/flutter#180596)
2026-01-06 dkwingsmt@users.noreply.github.com Enable misc leak tracking (flutter/flutter#176992)
2026-01-06 dacoharkes@google.com [hooks] Don't require NDK for Android targets (flutter/flutter#180594)
2026-01-06 kjlubick@users.noreply.github.com [skia] Disable legacy non-const SkData APIs (flutter/flutter#179684)
2026-01-06 48625061+muradhossin@users.noreply.github.com Fix/ios share context menu (flutter/flutter#176199)
2026-01-06 engine-flutter-autoroll@skia.org Roll Skia from b970aeffa66f to f5d9da13d56d (5 revisions) (flutter/flutter#180588)
2026-01-06 goderbauer@google.com Manually bump dependencies (flutter/flutter#180509)
2026-01-06 engine-flutter-autoroll@skia.org Roll Dart SDK from 8150be8a0e48 to 40a8c6188f7f (2 revisions) (flutter/flutter#180582)
2026-01-06 engine-flutter-autoroll@skia.org Roll Packages from 12eb764 to d3f860d (2 revisions) (flutter/flutter#180581)
2026-01-06 engine-flutter-autoroll@skia.org Roll Fuchsia Test Scripts from MHF-UAfO6sVKqSEYk... to nR2ESa1Gd8yPcWo06... (flutter/flutter#180578)
2026-01-06 sokolovskyi.konstantin@gmail.com Add tooltip support to PlatformMenuItem and PlatformMenu. (flutter/flutter#180069)
2026-01-06 bruno.leroux@gmail.com Add DropdownMenuFormField.errorBuilder (flutter/flutter#179345)
2026-01-06 engine-flutter-autoroll@skia.org Roll Skia from 1845397e11ba to b970aeffa66f (2 revisions) (flutter/flutter#180566)
2026-01-06 oss@simonbinder.eu Don't embed unreferenced assets (flutter/flutter#179251)
2026-01-06 116356835+AbdeMohlbi@users.noreply.github.com Improve documentation about ValueNotifier's behavior (flutter/flutter#179870)
2026-01-06 engine-flutter-autoroll@skia.org Roll Skia from 904ba00331ca to 1845397e11ba (5 revisions) (flutter/flutter#180558)
2026-01-06 engine-flutter-autoroll@skia.org Roll Dart SDK from 2fb9ad834c4d to 8150be8a0e48 (1 revision) (flutter/flutter#180557)
2026-01-06 engine-flutter-autoroll@skia.org Roll Skia from 98c042dde68c to 904ba00331ca (3 revisions) (flutter/flutter#180550)
2026-01-06 engine-flutter-autoroll@skia.org Roll Dart SDK from ba9f7f790966 to 2fb9ad834c4d (2 revisions) (flutter/flutter#180548)
2026-01-06 engine-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from ubBGcRaAKWKihQ4ac... to QfR2ZFZ5kGTD3raO3... (flutter/flutter#180547)
2026-01-06 ahmedsameha1@gmail.com Make sure that a DraggableScrollableSheet doesn't crash in 0x0 enviro… (flutter/flutter#180433)
2026-01-06 ahmedsameha1@gmail.com Make sure that a ColorFiltered doesn't crash 0x0 environment (flutter/flutter#180307)
2026-01-06 ahmedsameha1@gmail.com Make sure that a FadeInImage doesn't crash in 0x0 environment (flutter/flutter#180495)
...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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.

DropdownMenuEntry style's text style is not resolving with states

2 participants