Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Dropdown] Introduce higher-level menu component #37667

Merged
merged 54 commits into from
Jul 25, 2023

Conversation

michaldudak
Copy link
Member

@michaldudak michaldudak commented Jun 21, 2023

This PR introduces hooks and components that aim to make building menus easier. The general shape was discussed in #32088.

One notable change from what was discussed in the linked issue is the name of the outermost component. We agreed to use MenuProvider, but this name is already used elsewhere in Base UI. I decided to call the component (and the associated hook) DropdownMenu. Similarly to MenuProvider, this won't conflict with any existing identifiers from Material UI.

The structure currently looks as follows:

<DropdownMenu>
  <MenuButton>Menu</MenuButton>
  <Menu>
    <MenuItem>Item 1</MenuItem>
    <MenuItem>Item 2</MenuItem>
    <MenuItem>Item 3</MenuItem>
  </Menu>
</DropdownMenu>

I'm looking forward to seeing opinions about this naming pattern. I'm considering renaming the Menu to MenuList to make it less ambiguous.

As for the implementation, controlling the open/close state is done via a controllable reducer owned by the DropdownMenu. Menu and MenuItem dispatch actions, and the whole logic sits in dropdownMenuReducer. The dispatch function could be exposed externally in the future if needed. Such architecture allows for easy communication between components and enables painless introduction of other menu items, such as radio button or checkbox going forward.

⚠️ Breaking change

This PR changes how menus are used. Instead of custom wiring of a menu and a button to open/close it, place the Menu and the MenuButton within a Dropdown component. The open and onOpenChange props now are accepted by the Dropdown, not the menu.

Playground: https://deploy-preview-37667--material-ui.netlify.app/experiments/base/menu/

Closes #32088

@michaldudak michaldudak added component: menu This is the name of the generic UI component, not the React module! package: base-ui Specific to @mui/base labels Jun 21, 2023
@mui-bot
Copy link

mui-bot commented Jun 21, 2023

Netlify deploy preview

@material-ui/unstyled: parsed: +2.92% , gzip: +2.45%
@mui/joy: parsed: +1.39% , gzip: +1.52%

Bundle size report

Details of bundle changes (Toolpad)
Details of bundle changes

Generated by 🚫 dangerJS against dafec79

@siriwatknp
Copy link
Member

👏 Love it!

Copy link
Member

@siriwatknp siriwatknp left a comment

Choose a reason for hiding this comment

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

For the naming, here is my thought

  • Dropdown sounds better and shorter than DropdownMenu without losing the meaning.
  • I don't agree to change Menu to MenuList because that will introduce a big change to the codebase and to developers (I think the Menu works great).

@michaldudak
Copy link
Member Author

michaldudak commented Jun 23, 2023

Dropdown sounds better and shorter than DropdownMenu without losing the meaning.

Interesting idea. I'm not sure I', 100% sold, but I'll consider it. When we add a context menu in the future, I wonder what the naming scheme should be. <Context> itself is a no-go, so we'd need <ContextMenu>. But alternatively, we could say that a context menu is also a dropdown menu, just with a different trigger, so it could look like this:

<Dropdown>
  <ContextTrigger element={ref} />
  <Menu>...</Menu>
</Dropdown>

While it's something for the future, it could be worth having this at the back of our heads we create an intuitive API.

@michaldudak michaldudak added this to the Base UI: Stable release milestone Jun 23, 2023
@mnajdova
Copy link
Member

On the naming, I would go with Dropdown as well, however, there is slight difference in what we consider Dropdown, vs what other libraries are considering it, for e.g. fluent ui - https://developer.microsoft.com/en-us/fluentui#/controls/web/dropdown, https://www.downshift-js.com/use-combobox#materialui - it seems to be more associated with the autocomplete. If we consider this, maybe DropdownMenu is a better name.

@michaldudak
Copy link
Member Author

But in our case, we still have a Menu component inside, so it's more clear, I guess. So essentially, the Dropdown component would implement a pretty generic concept of dropdown-anything, and we will use it to build the Menu, but in theory it could be used in a more popover-like way.

@mnajdova
Copy link
Member

But in our case, we still have a Menu component inside, so it's more clear, I guess. So essentially, the Dropdown component would implement a pretty generic concept of dropdown-anything, and we will use it to build the Menu, but in theory it could be used in a more popover-like way.

Fair enough, let's go with Dropdown only then for the start. I am wondering whether we should make this unstable at start, similarly to the NumberInput, and stabilize it once we have enough feedback on it. That way, we can experiment and change the name later if it creates confusion. What do you think?

@michaldudak
Copy link
Member Author

A problem with this approach is that we'd have to make the Menu unstable as well as it had to be adjusted to work with the Dropdown

@michaldudak
Copy link
Member Author

@siriwatknp I'll introduce these changes to Joy as well. Are you OK with it?

@github-actions github-actions bot added the PR: out-of-date The pull request has merge conflicts and can't be merged label Jun 28, 2023
@siriwatknp
Copy link
Member

@siriwatknp I'll introduce these changes to Joy as well. Are you OK with it?

Sounds good to me!

@siriwatknp
Copy link
Member

@siriwatknp I'll introduce these changes to Joy as well. Are you OK with it?

Sounds good to me!

Thinking about it again. Would it be better to separate the PR? easier to review and track in the changelog.

@michaldudak
Copy link
Member Author

Merging just the changes from Base UI would leave Joy UI broken as the Base Menu's API was changed.
I can create a separate PR based on this branch to it's easier to review

@github-actions github-actions bot removed the PR: out-of-date The pull request has merge conflicts and can't be merged label Jun 28, 2023
@github-actions github-actions bot removed the PR: out-of-date The pull request has merge conflicts and can't be merged label Jul 14, 2023
Copy link
Member

@DiegoAndai DiegoAndai left a comment

Choose a reason for hiding this comment

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

This is a great utility component, I think it completely delivers on the promise of making easier the building of dropdown menus 🎉

Regarding naming, Dropdown and Menu sound good to me, at the beginning, I was also thinking MenuList would have been better but the role is menu and on the ARIA design patterns they name it Menu as well, so I think it's consistent with the ecosystem.

It's a complex problem and thus complex implementation so reviewing was hard. I got the general picture of how it works and it makes sense to me, as well as how it was implemented, so I'm approving.

I just left a little comment/question.

I think we should wait for @siriwatknp to review and approve the Joy changes

import { useTheme } from '@mui/system';
import { ListActionTypes } from '@mui/base/useList';

export default function UnstyledMenuSimple() {
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't we replace the "Unstyled" prefixes for "Base"? Or are we keeping the "Unstyled"? I think it might be confusing. Maybe just use "MenuSimple"

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, good point. I'll create a separate PR for this.

@michaldudak michaldudak force-pushed the menubutton branch 2 times, most recently from 42fe487 to cbdc759 Compare July 17, 2023 09:11
@michaldudak
Copy link
Member Author

@siriwatknp I'd appreciate if you could double-check the changes in Joy.

@siriwatknp
Copy link
Member

@siriwatknp I'd appreciate if you could double-check the changes in Joy.

Got it.

Copy link
Member

@siriwatknp siriwatknp left a comment

Choose a reason for hiding this comment

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

👍 Looks great!

@github-actions github-actions bot added the PR: out-of-date The pull request has merge conflicts and can't be merged label Jul 20, 2023
@github-actions github-actions bot removed the PR: out-of-date The pull request has merge conflicts and can't be merged label Jul 24, 2023
@michaldudak michaldudak merged commit fbc4c66 into mui:master Jul 25, 2023
22 checks passed
@michaldudak michaldudak deleted the menubutton branch July 25, 2023 13:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking change component: menu This is the name of the generic UI component, not the React module! package: base-ui Specific to @mui/base
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[MenuButton][base] Create the MenuButtonUnstyled component
5 participants