Skip to content

Fix DropdownMenuEntry.style not resolved when entry is highlighted#178873

Merged
auto-submit[bot] merged 1 commit intoflutter:masterfrom
bleroux:fix_DropdownMenuEntry_styles_not_resolving
Jan 7, 2026
Merged

Fix DropdownMenuEntry.style not resolved when entry is highlighted#178873
auto-submit[bot] merged 1 commit intoflutter:masterfrom
bleroux:fix_DropdownMenuEntry_styles_not_resolving

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 +885
_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 +885
_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 +924
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 +885
_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 [email protected] Replace Hybrid Composition wiki page with dev-facing content (flutter/flutter#180642)
2026-01-07 [email protected] Improve code quality in `FlutterActivityTest.java` (flutter/flutter#180585)
2026-01-07 [email protected] Roll Dart SDK to 3.11.0-296.1.beta (flutter/flutter#180633)
2026-01-07 [email protected] Bump target Windows version to 10 (flutter/flutter#180624)
2026-01-07 [email protected] Run hook_user_defines and link_hook integration tests on CI (flutter/flutter#180622)
2026-01-07 [email protected] Fix division by zero in RenderTable intrinsic size methods (flutter/flutter#178217)
2026-01-07 [email protected] Remove more  `requires 24` anotations (flutter/flutter#180116)
2026-01-07 [email protected] Roll Skia from 3971dbb85d45 to c5359a4d720e (1 revision) (flutter/flutter#180631)
2026-01-07 [email protected] Fix TabBar.image does not render at initialIndex for the first time (flutter/flutter#179616)
2026-01-07 [email protected] Roll Skia from 1e7ad625f6f7 to 3971dbb85d45 (3 revisions) (flutter/flutter#180627)
2026-01-07 [email protected] Unpin DDS (flutter/flutter#180571)
2026-01-07 [email protected] Fix DropdownMenuEntry.style not resolved when entry is highlighted (flutter/flutter#178873)
2026-01-07 [email protected] Remove unnecessary `@RequiresApi24` annotations from FlutterFragment methods (flutter/flutter#180117)
2026-01-07 [email protected] Roll Skia from 7fc63228056b to 1e7ad625f6f7 (1 revision) (flutter/flutter#180616)
2026-01-07 [email protected] Roll Fuchsia Linux SDK from QfR2ZFZ5kGTD3raO3... to dTvN_JVSCfGFRasvH... (flutter/flutter#180612)
2026-01-07 [email protected] [ Widget Preview ] Add support for `dart:ffi` imports (flutter/flutter#180586)
2026-01-07 [email protected] Roll Skia from eec90000a899 to 7fc63228056b (2 revisions) (flutter/flutter#180608)
2026-01-07 [email protected] Add --web-define flag for template variable injection in Flutter web builds (flutter/flutter#175805)
2026-01-07 [email protected] docs(engine): update rbe notes (flutter/flutter#180599)
2026-01-06 [email protected] Roll Skia from b6249496c230 to eec90000a899 (3 revisions) (flutter/flutter#180602)
2026-01-06 [email protected] Forward proxy 404 responses to client (flutter/flutter#179858)
2026-01-06 [email protected] Roll Dart SDK from 40a8c6188f7f to d2e3ce177270 (1 revision) (flutter/flutter#180598)
2026-01-06 [email protected] Restore CLI precedence for web headers and HTTPS over web_dev_config.yaml (flutter/flutter#179639)
2026-01-06 [email protected] Roll Skia from f5d9da13d56d to b6249496c230 (1 revision) (flutter/flutter#180596)
2026-01-06 [email protected] Enable misc leak tracking (flutter/flutter#176992)
2026-01-06 [email protected] [hooks] Don't require NDK for Android targets (flutter/flutter#180594)
2026-01-06 [email protected] [skia] Disable legacy non-const SkData APIs (flutter/flutter#179684)
2026-01-06 [email protected] Fix/ios share context menu (flutter/flutter#176199)
2026-01-06 [email protected] Roll Skia from b970aeffa66f to f5d9da13d56d (5 revisions) (flutter/flutter#180588)
2026-01-06 [email protected] Manually bump dependencies (flutter/flutter#180509)
2026-01-06 [email protected] Roll Dart SDK from 8150be8a0e48 to 40a8c6188f7f (2 revisions) (flutter/flutter#180582)
2026-01-06 [email protected] Roll Packages from 12eb764 to d3f860d (2 revisions) (flutter/flutter#180581)
2026-01-06 [email protected] Roll Fuchsia Test Scripts from MHF-UAfO6sVKqSEYk... to nR2ESa1Gd8yPcWo06... (flutter/flutter#180578)
2026-01-06 [email protected] Add tooltip support to PlatformMenuItem and PlatformMenu. (flutter/flutter#180069)
2026-01-06 [email protected] Add DropdownMenuFormField.errorBuilder (flutter/flutter#179345)
2026-01-06 [email protected] Roll Skia from 1845397e11ba to b970aeffa66f (2 revisions) (flutter/flutter#180566)
2026-01-06 [email protected] Don't embed unreferenced assets (flutter/flutter#179251)
2026-01-06 [email protected] Improve documentation about ValueNotifier's behavior (flutter/flutter#179870)
2026-01-06 [email protected] Roll Skia from 904ba00331ca to 1845397e11ba (5 revisions) (flutter/flutter#180558)
2026-01-06 [email protected] Roll Dart SDK from 2fb9ad834c4d to 8150be8a0e48 (1 revision) (flutter/flutter#180557)
2026-01-06 [email protected] Roll Skia from 98c042dde68c to 904ba00331ca (3 revisions) (flutter/flutter#180550)
2026-01-06 [email protected] Roll Dart SDK from ba9f7f790966 to 2fb9ad834c4d (2 revisions) (flutter/flutter#180548)
2026-01-06 [email protected] Roll Fuchsia Linux SDK from ubBGcRaAKWKihQ4ac... to QfR2ZFZ5kGTD3raO3... (flutter/flutter#180547)
2026-01-06 [email protected] Make sure that a DraggableScrollableSheet doesn't crash in 0x0 enviro… (flutter/flutter#180433)
2026-01-06 [email protected] Make sure that a ColorFiltered doesn't crash 0x0 environment (flutter/flutter#180307)
2026-01-06 [email protected] Make sure that a FadeInImage doesn't crash in 0x0 environment (flutter/flutter#180495)
...
ivan-vanyusho pushed a commit to ivan-vanyusho/packages that referenced this pull request Jan 26, 2026
Roll Flutter from 13b2b91 to 01d37bc (74 revisions)

flutter/flutter@13b2b91...01d37bc

2026-01-07 [email protected] Replace Hybrid Composition wiki page with dev-facing content (flutter/flutter#180642)
2026-01-07 [email protected] Improve code quality in `FlutterActivityTest.java` (flutter/flutter#180585)
2026-01-07 [email protected] Roll Dart SDK to 3.11.0-296.1.beta (flutter/flutter#180633)
2026-01-07 [email protected] Bump target Windows version to 10 (flutter/flutter#180624)
2026-01-07 [email protected] Run hook_user_defines and link_hook integration tests on CI (flutter/flutter#180622)
2026-01-07 [email protected] Fix division by zero in RenderTable intrinsic size methods (flutter/flutter#178217)
2026-01-07 [email protected] Remove more  `requires 24` anotations (flutter/flutter#180116)
2026-01-07 [email protected] Roll Skia from 3971dbb85d45 to c5359a4d720e (1 revision) (flutter/flutter#180631)
2026-01-07 [email protected] Fix TabBar.image does not render at initialIndex for the first time (flutter/flutter#179616)
2026-01-07 [email protected] Roll Skia from 1e7ad625f6f7 to 3971dbb85d45 (3 revisions) (flutter/flutter#180627)
2026-01-07 [email protected] Unpin DDS (flutter/flutter#180571)
2026-01-07 [email protected] Fix DropdownMenuEntry.style not resolved when entry is highlighted (flutter/flutter#178873)
2026-01-07 [email protected] Remove unnecessary `@RequiresApi24` annotations from FlutterFragment methods (flutter/flutter#180117)
2026-01-07 [email protected] Roll Skia from 7fc63228056b to 1e7ad625f6f7 (1 revision) (flutter/flutter#180616)
2026-01-07 [email protected] Roll Fuchsia Linux SDK from QfR2ZFZ5kGTD3raO3... to dTvN_JVSCfGFRasvH... (flutter/flutter#180612)
2026-01-07 [email protected] [ Widget Preview ] Add support for `dart:ffi` imports (flutter/flutter#180586)
2026-01-07 [email protected] Roll Skia from eec90000a899 to 7fc63228056b (2 revisions) (flutter/flutter#180608)
2026-01-07 [email protected] Add --web-define flag for template variable injection in Flutter web builds (flutter/flutter#175805)
2026-01-07 [email protected] docs(engine): update rbe notes (flutter/flutter#180599)
2026-01-06 [email protected] Roll Skia from b6249496c230 to eec90000a899 (3 revisions) (flutter/flutter#180602)
2026-01-06 [email protected] Forward proxy 404 responses to client (flutter/flutter#179858)
2026-01-06 [email protected] Roll Dart SDK from 40a8c6188f7f to d2e3ce177270 (1 revision) (flutter/flutter#180598)
2026-01-06 [email protected] Restore CLI precedence for web headers and HTTPS over web_dev_config.yaml (flutter/flutter#179639)
2026-01-06 [email protected] Roll Skia from f5d9da13d56d to b6249496c230 (1 revision) (flutter/flutter#180596)
2026-01-06 [email protected] Enable misc leak tracking (flutter/flutter#176992)
2026-01-06 [email protected] [hooks] Don't require NDK for Android targets (flutter/flutter#180594)
2026-01-06 [email protected] [skia] Disable legacy non-const SkData APIs (flutter/flutter#179684)
2026-01-06 [email protected] Fix/ios share context menu (flutter/flutter#176199)
2026-01-06 [email protected] Roll Skia from b970aeffa66f to f5d9da13d56d (5 revisions) (flutter/flutter#180588)
2026-01-06 [email protected] Manually bump dependencies (flutter/flutter#180509)
2026-01-06 [email protected] Roll Dart SDK from 8150be8a0e48 to 40a8c6188f7f (2 revisions) (flutter/flutter#180582)
2026-01-06 [email protected] Roll Packages from 12eb764 to d3f860d (2 revisions) (flutter/flutter#180581)
2026-01-06 [email protected] Roll Fuchsia Test Scripts from MHF-UAfO6sVKqSEYk... to nR2ESa1Gd8yPcWo06... (flutter/flutter#180578)
2026-01-06 [email protected] Add tooltip support to PlatformMenuItem and PlatformMenu. (flutter/flutter#180069)
2026-01-06 [email protected] Add DropdownMenuFormField.errorBuilder (flutter/flutter#179345)
2026-01-06 [email protected] Roll Skia from 1845397e11ba to b970aeffa66f (2 revisions) (flutter/flutter#180566)
2026-01-06 [email protected] Don't embed unreferenced assets (flutter/flutter#179251)
2026-01-06 [email protected] Improve documentation about ValueNotifier's behavior (flutter/flutter#179870)
2026-01-06 [email protected] Roll Skia from 904ba00331ca to 1845397e11ba (5 revisions) (flutter/flutter#180558)
2026-01-06 [email protected] Roll Dart SDK from 2fb9ad834c4d to 8150be8a0e48 (1 revision) (flutter/flutter#180557)
2026-01-06 [email protected] Roll Skia from 98c042dde68c to 904ba00331ca (3 revisions) (flutter/flutter#180550)
2026-01-06 [email protected] Roll Dart SDK from ba9f7f790966 to 2fb9ad834c4d (2 revisions) (flutter/flutter#180548)
2026-01-06 [email protected] Roll Fuchsia Linux SDK from ubBGcRaAKWKihQ4ac... to QfR2ZFZ5kGTD3raO3... (flutter/flutter#180547)
2026-01-06 [email protected] Make sure that a DraggableScrollableSheet doesn't crash in 0x0 enviro… (flutter/flutter#180433)
2026-01-06 [email protected] Make sure that a ColorFiltered doesn't crash 0x0 environment (flutter/flutter#180307)
2026-01-06 [email protected] Make sure that a FadeInImage doesn't crash in 0x0 environment (flutter/flutter#180495)
...
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Feb 11, 2026
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