Skip to content

Conversation

@wellingtoncosta
Copy link
Collaborator

@wellingtoncosta wellingtoncosta commented Feb 5, 2026

Summary

This PR introduces a significant refactoring of PopupMenu to use PopupContainer instead of directly using Popup, consolidating visual styling (shadows, borders, backgrounds) and scrolling logic in one place. Previously, MenuContent had its own implementation of these features; now PopupContainer handles all popup styling consistently across the application, with MenuContent focusing solely on rendering menu items. Both menu content and ad content are now in the same scrollable area within PopupContainer.

To support this refactoring, PopupContainer was enhanced with scrolling support via maxHeight, useIntrinsicWidth for width control, and key event handling. The PopupMenu API now accepts both menuStyle and popupContainerStyle parameters to better separate menu item styling from container styling.

Additionally, this PR introduces MenuComboBox, a modern replacement for the deprecated Dropdown component that combines ComboBox UI with MenuContent for richer popup functionality including icons, keybindings, separators, and submenus. The component provides better keyboard navigation, focus management, and accessibility support.

Showcase samples were updated to demonstrate MenuComboBox usage.

Screen recording

Screen.Recording.2026-02-05.at.11.51.22.AM.mov

Release notes

⚠️ Important Changes

  • JEWEL-1230 Dropdown component is now deprecated in favor of MenuComboBox, which provides better keyboard navigation and accessibility support with automatic replacement provided

New features

  • JEWEL-1029 Added scrolling support to PopupContainer with optional maxHeight parameter and vertical scrollbar
  • JEWEL-1029 Added useIntrinsicWidth parameter to PopupContainer for controlling width measurement (set to false for SubcomposeLayout-based components like LazyColumn)
  • JEWEL-1029 Added key event handling to PopupContainer via onPreviewKeyEvent and onKeyEvent parameters
  • JEWEL-1029 Added PopupMenu overloads accepting both menuStyle and popupContainerStyle for better separation of menu item styling from container styling
  • JEWEL-1230 Introduced experimental MenuComboBox as modern Dropdown replacement with support for menu items with icons, keybindings, separators, and submenus

Deprecated API

  • JEWEL-1230 Deprecated Dropdown in favor of MenuComboBox with DeprecationLevel.WARNING
  • JEWEL-1029 Deprecated older PopupContainer, PopupMenu, and ComboBox overloads in favor of new variants with enhanced parameters

Note

Medium Risk
Touches core popup/menu/combobox UI primitives and keyboard handling, so regressions in sizing, focus, and dismissal behavior are possible despite the changes being largely contained to UI infrastructure.

Overview
Reimplements dropdown-style menus by introducing experimental MenuComboBox (menu-item popup with icons/separators/submenus) and deprecating Dropdown with an auto ReplaceWith.

Refactors PopupMenu to render via PopupContainer (centralizing border/shadow/background, optional scrolling via maxHeight, and container styling) and simplifies MenuContent to focus on item rendering; updates call sites to the new menuStyle/popupContainerStyle parameter split.

Extends PopupContainer (scrolling + scrollbar, useIntrinsicWidth, key event hooks) and adds an experimental ComboBox overload to pass PopupProperties, popup key handling, and intrinsic-width control; updates the showcase sample to demonstrate MenuComboBox and refreshes API dumps.

Written by Cursor Bugbot for commit 96b26ca. This will update automatically on new commits. Configure here.

adContent?.let { PopupAd(modifier = Modifier.fillMaxWidth()) { it() } }
MenuStyle(isDark = style.isDark, colors = style.colors, metrics = adjustedMetrics, icons = style.icons)
} else {
style
Copy link

Choose a reason for hiding this comment

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

useFullWidthSelection flag has no effect on metrics

Medium Severity

The useFullWidthSelection parameter in MenuContentImpl is intended to adjust menu item metrics for full-width selection highlighting, but the adjustedItemMetrics construction simply copies all values from the original itemMetrics without any modifications. The outerPadding field (which controls the selection highlight inset) is copied unchanged, making the entire conditional branch a no-op. This affects MenuComboBox, which explicitly sets useFullWidthSelection = true expecting adjusted selection visuals.

Additional Locations (1)

Fix in Cursor Fix in Web

Copy link
Collaborator

@DanielSouzaBertoldi DanielSouzaBertoldi left a comment

Choose a reason for hiding this comment

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

Awesome stuff! 🚀

Just some minor changes + a little nit-picking 😈

Comment on lines 261 to 263
Copy link
Collaborator

@DanielSouzaBertoldi DanielSouzaBertoldi Feb 6, 2026

Choose a reason for hiding this comment

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

I think it's best to make this distinction as early as possible in the KDoc, since the idea is to strongly suggest users to use this variant from now on, right?

Suggested change
* This version of ComboBox allows for complete customization of the label area through a composable function and also includes additional parameters for controlling popup behavior, keyboard events, and width measurement.

And also add the reason why this variant is the one users should stick with 90% of the time

Comment on lines 273 to 275
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
* @param useIntrinsicPopupWidth Whether to use intrinsic width measurement for the popup. Set it to `true` when the popup
* content must size itself to its widest item (e.g., `MenuContent`). Set to false (default) when the content contains
* `SubcomposeLayout`-based components (`LazyColumn`, `LazyRow`, etc.) which don't support intrinsic measurements

Copy link
Collaborator

Choose a reason for hiding this comment

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

In the KDoc it's stated that this parameter has a default value of false, but that's not the case in the actual code.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Once your PR is merged, I'll have to make sure to add a variant that does not let the user set the maxPopupHeight but instead should be high enough for an arbitrary number of rows to appear at once in my PR (#3384)

Copy link
Collaborator

Choose a reason for hiding this comment

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

Why is the default for focusable false? Thinking as a user, I'd probably like to have the popup automatically gain focus once I click something that opens it.

Also, this property is set as true by default in the PopupMenu variant that you added

Or is there some context here I'm missing? 🤯

Copy link
Collaborator

Choose a reason for hiding this comment

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

Not sure if this was changed. Every other code here sets focusable as true, but this is still false. Is this expected?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Sorry, I don't get it. If users don't set a maxHeight then the content will scroll independently from the adContent?

Or by "original behavior" you mean the fact that maybe there's no vertical scroll at all?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I reworked this to be more intuitive rephrased these comments. Also found a subtle bug in some combo box samples regarding measurement. Things are now more clear and working.

Copy link
Collaborator

@DanielSouzaBertoldi DanielSouzaBertoldi Feb 11, 2026

Choose a reason for hiding this comment

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

It's always a good idea to add tests to check if the bugs you found have been fixed for good. It also protect us in the future if the bug happens to come again after some changes 😎

@wellingtoncosta
Copy link
Collaborator Author

@DanielSouzaBertoldi I resolved all your comments (I hope so), so please take a look on this PR again once you have a chance. Let me know if you have more questions or concerns.

@wellingtoncosta wellingtoncosta force-pushed the wp/reimplement-dropdown-component branch from f0e4d72 to 5d93115 Compare February 9, 2026 23:16
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

@wellingtoncosta wellingtoncosta force-pushed the wp/reimplement-dropdown-component branch from 5d93115 to d9be05c Compare February 9, 2026 23:38
@wellingtoncosta wellingtoncosta force-pushed the wp/reimplement-dropdown-component branch from d9be05c to 96b26ca Compare February 9, 2026 23:55
@DanielSouzaBertoldi
Copy link
Collaborator

@wellingtoncosta I noticed some changes are still pending. Let me know once you reply to my comments/add the changes, please

onPopupVisibleChange: (visible: Boolean) -> Unit = {},
content: MenuScope.() -> Unit,
) {
val popupManager = remember { PopupManager(onPopupVisibleChange) }
Copy link
Collaborator

@DanielSouzaBertoldi DanielSouzaBertoldi Feb 11, 2026

Choose a reason for hiding this comment

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

This code is still not keying on onPopupVisibleChange or updated to use rememberUpdatedState instead.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants