Menus display a list of choices on a transient sheet of material.
- Module @rmwc/menu
- Import styles:
- Using CSS Loader
- import '@rmwc/menu/styles';
- Or include stylesheets
- '@material/menu/dist/mdc.menu.css'
- '@material/menu-surface/dist/mdc.menu-surface.css'
- '@material/ripple/dist/mdc.ripple.css'
- '@material/list/dist/mdc.list.css'
- '@rmwc/icon/icon.css'
- Using CSS Loader
- MDC Docs: https://material.io/develop/web/components/menus/
You can compose a menu with the given components, and manually manage the open state. Menu
expects MenuItems as children while MenuSurface
is a generic container which can have anything as a child.
function Example() {
const [open, setOpen] = React.useState(false);
return (
<MenuSurfaceAnchor>
<Menu
open={open}
onSelect={(evt) => console.log(evt.detail.index)}
onClose={() => setOpen(false)}
>
<MenuItem>Cookies</MenuItem>
<MenuItem>Pizza</MenuItem>
{/** MenuItem is just a ListItem, so you can intermingle other List components */}
<ListDivider />
<MenuItem>Icecream</MenuItem>
</Menu>
<Button raised onClick={() => setOpen(!open)}>
Menu
</Button>
</MenuSurfaceAnchor>
);
}
function Example() {
const [open, setOpen] = React.useState(false);
return (
<MenuSurfaceAnchor>
<MenuSurface open={open} onClose={(evt) => setOpen(false)}>
<div style={{ padding: '1rem', width: '8rem' }}>
Make the content whatever you want.
</div>
</MenuSurface>
<Button raised onClick={(evt) => setOpen(!open)}>
Menu Surface
</Button>
</MenuSurfaceAnchor>
);
}
function Example() {
const [open, setOpen] = React.useState(false);
return (
<MenuSurfaceAnchor>
<MenuSurface open={open} onClose={() => setOpen(false)}>
<div style={{ padding: '1rem', width: '8rem' }}>Menu</div>
</MenuSurface>
{/** The handle can be any component you want */}
<IconButton icon="menu" onClick={() => setOpen(!open)} />
</MenuSurfaceAnchor>
);
}
function Example() {
const [open, setOpen] = React.useState(false);
return (
<MenuSurfaceAnchor>
<Menu
open={open}
onSelect={(evt) => console.log(evt.detail.index)}
onClose={() => setOpen(false)}
>
<MenuItem>Item One</MenuItem>
<MenuItem disabled>Item Two (disabled)</MenuItem>
<MenuItem>Item Three</MenuItem>
</Menu>
<Button raised onClick={() => setOpen(!open)}>
Menu
</Button>
</MenuSurfaceAnchor>
);
}
RMWC provides a convenience SimpleMenu
component that takes a handle as a prop, and manages the open state for you.
<SimpleMenu handle={<Button>Simple Menu</Button>}>
<MenuItem>Cookies</MenuItem>
<MenuItem>Pizza</MenuItem>
<MenuItem>Icecream</MenuItem>
</SimpleMenu>
<SimpleMenuSurface handle={<Button>Simple Menu Surface</Button>}>
<div style={{ padding: '1rem', width: '8rem' }}>
Make the content whatever you want.
</div>
</SimpleMenuSurface>
By default, Menus will attempt to automatically position themselves, but this behavior can be overridden by setting the anchorCorner
prop.
function Example() {
const [anchorCorner, setAnchorCorner] =
React.useState('topLeft');
return (
<>
<MenuSurfaceAnchor>
<MenuSurface anchorCorner={anchorCorner} open={true}>
<div style={{ padding: '1rem', width: '8rem' }}>
anchorCorner: {anchorCorner}
</div>
</MenuSurface>
<Button raised label="Anchored Menu" />
</MenuSurfaceAnchor>
<Select
value={anchorCorner}
label="anchorCorner"
onChange={(evt) => setAnchorCorner(evt.currentTarget.value)}
options={[
'topLeft',
'topRight',
'bottomLeft',
'bottomRight',
'topStart',
'topEnd',
'bottomStart',
'bottomEnd'
]}
/>
</>
);
}
Occasionally, you may find your menu being cut off from being inside a container that is styled to be overflow:hidden
. RMWC provides a renderToPortal
prop that lets you use React's portal functionality to render the menu dropdown in a different container.
You can specify any element or selector you want, but the simplest method is to pass true
and use RMWC's built in Portal
component.
`
// Somewhere at the top level of your app
// Render the RMWC Portal
// You only have to do this once
import React from 'react';
import { Portal } from '@rmwc/base';
export default function App() {
return (
<div>
...
<Portal />
</div>
)
}
`
Now you can use the renderToPortal
prop. Below is a contrived example of a menu being cut off due to overflow: hidden
.
function Example() {
const [renderToPortal, setRenderToPortal] = React.useState(true);
const [menuIsOpen, setMenuIsOpen] = React.useState(false);
const options = ['Cookies', 'Pizza', 'Icecream'];
return (
<>
<div
style={{
marginBottom: '10rem',
height: '3.5rem',
overflow: 'hidden'
}}
>
<MenuSurfaceAnchor>
<Button raised onClick={() => setMenuIsOpen(!menuIsOpen)}>
Open Menu
</Button>
<Menu
open={menuIsOpen}
onClose={() => setMenuIsOpen(false)}
renderToPortal={renderToPortal}
>
{options.map((o) => (
<MenuItem key={o}>{o}</MenuItem>
))}
</Menu>
</MenuSurfaceAnchor>
</div>
<Checkbox
checked={renderToPortal}
onChange={(evt) => setRenderToPortal(evt.currentTarget.checked)}
label="renderToPortal"
/>
</>
);
}
A menu component for displaying lists items.
Name | Type | Description |
---|---|---|
anchorCorner |
AnchorT |
Manually position the menu to one of the corners. |
apiRef |
(api: null | MenuApi) => void |
Internal api reference for cross component communication. |
children |
ReactNode |
Children to render. |
fixed |
boolean |
Make the menu position fixed. |
focusOnOpen |
boolean |
Whether or not to focus the first list item on open. Defaults to true. |
foundationRef |
Ref<MDCMenuFoundation<>> |
Advanced: A reference to the MDCFoundation. |
onClose |
(evt: MenuSurfaceOnCloseEventT) => void |
Callback for when the menu is closed. |
onOpen |
(evt: MenuSurfaceOnOpenEventT) => void |
Callback for when the menu is opened. |
onSelect |
(evt: MenuOnSelectEventT) => void |
Callback that fires when a Menu item is selected. evt.detail = { index: number; item: HTMLElement; } |
open |
boolean |
Opens the menu. |
renderToPortal |
PortalPropT |
Renders the menu to a portal. Useful for situations where the content might be cutoff by an overflow: hidden container. You can pass "true" to render to the default RMWC portal. |
This is just the ListItem component exported from the Menu module for convenience. You can use
ListItem
or
SimpleListItem
components from the List section as long as you add
role="menuitem"
and
tabIndex="0"
to the components for accessibility.
Name | Type | Description |
---|---|---|
activated |
boolean |
A modifier for an active state. |
disabled |
boolean |
A modifier for a disabled state. |
ripple |
RipplePropT |
Adds a ripple effect to the component |
selected |
boolean |
A modifier for a selected state. |
Name | Type | Description |
---|---|---|
anchorCorner |
AnchorT |
Manually position the menu to one of the corners. |
apiRef |
(api: null | MenuSurfaceApi) => void |
An internal api for cross component communication. |
children |
ReactNode |
Children to render. |
fixed |
boolean |
Make the menu position fixed. |
foundationRef |
Ref<MDCMenuSurfaceFoundation<>> |
Advanced: A reference to the MDCFoundation. |
onClose |
(evt: MenuSurfaceOnCloseEventT) => void |
Callback for when the menu is closed. |
onOpen |
(evt: MenuSurfaceOnOpenEventT) => void |
Callback for when the menu is opened. |
open |
boolean |
Opens the menu. |
renderToPortal |
PortalPropT |
Renders the menu to a portal. Useful for situations where the content might be cutoff by an overflow: hidden container. You can pass "true" to render to the default RMWC portal. |
MenuSurfaceAnchor
A Simplified menu component that allows you to pass a handle element and will automatically control the open state and add a MenuSurfaceAnchor
Name | Type | Description |
---|---|---|
anchorCorner |
AnchorT |
Manually position the menu to one of the corners. |
apiRef |
(api: null | MenuApi) => void |
Internal api reference for cross component communication. |
children |
ReactNode |
Children to render |
fixed |
boolean |
Make the menu position fixed. |
focusOnOpen |
boolean |
Whether or not to focus the first list item on open. Defaults to true. |
foundationRef |
Ref<MDCMenuFoundation<>> |
Advanced: A reference to the MDCFoundation. |
handle |
ReactElement<any, string | JSXElementConstructor<any>> |
An element that will open the menu when clicked |
onClose |
(evt: MenuSurfaceOnCloseEventT) => void |
Callback for when the menu is closed. |
onOpen |
(evt: MenuSurfaceOnOpenEventT) => void |
Callback for when the menu is opened. |
onSelect |
(evt: MenuOnSelectEventT) => void |
Callback that fires when a Menu item is selected. evt.detail = { index: number; item: HTMLElement; } |
open |
boolean |
Opens the menu. |
renderToPortal |
PortalPropT |
Renders the menu to a portal. Useful for situations where the content might be cutoff by an overflow: hidden container. You can pass "true" to render to the default RMWC portal. |
rootProps |
Object |
By default, props spread to the Menu component. These will spread to the MenuSurfaceAnchor which is useful for things like overall positioning of the anchor. |
The same as SimpleMenu, but a generic surface.
Name | Type | Description |
---|---|---|
anchorCorner |
AnchorT |
Manually position the menu to one of the corners. |
apiRef |
(api: null | MenuSurfaceApi) => void |
An internal api for cross component communication. |
children |
ReactNode |
Children to render |
fixed |
boolean |
Make the menu position fixed. |
foundationRef |
Ref<MDCMenuSurfaceFoundation<>> |
Advanced: A reference to the MDCFoundation. |
handle |
ReactElement<any, string | JSXElementConstructor<any>> |
An element that will open the menu when clicked |
onClose |
(evt: MenuSurfaceOnCloseEventT) => void |
Callback for when the menu is closed. |
onOpen |
(evt: MenuSurfaceOnOpenEventT) => void |
Callback for when the menu is opened. |
open |
boolean |
Opens the menu. |
renderToPortal |
PortalPropT |
Renders the menu to a portal. Useful for situations where the content might be cutoff by an overflow: hidden container. You can pass "true" to render to the default RMWC portal. |
rootProps |
Object |
By default, props spread to the Menu component. These will spread to the MenuSurfaceAnchor which is useful for things like overall positioning of the anchor. |