<IconMenu>
This Enterprise Edition component offers an alternative menu user interface. It renders a reduced menu bar with a sliding panel for second-level menu items. This menu saves a lot of screen real estate, and allows for sub menus of any level of complexity.
Sometimes, even menus with sub-menus are not enough to organize the navigation. ra-navigation
offers an alternative UI for that case: a vertical bar with small items, where the menu label renders underneath the icon. Clicking on any of those items opens a panel containing as many navigation links as you like, laid out as you wish.
Test it live on the Enterprise Edition Storybook.
Usage
Create a custom menu component using the <IconMenu>
and <IconMenu.Item>
components from the ra-navigation
package:
// in src/MyMenu.js
import { IconMenu } from "@react-admin/ra-navigation";
import DashboardIcon from '@mui/icons-material/Dashboard';
import MusicIcon from '@mui/icons-material/MusicNote';
import PeopleIcon from '@mui/icons-material/People';
const MyMenu = () => (
<IconMenu variant="categories">
<IconMenu.Item name="dashboard" to="/" label="Dashboard" icon={<DashboardIcon />} />
<IconMenu.Item name="songs" to="/songs" label="Songs" icon={<MusicIcon />} />
{/* The empty filter is required to avoid falling back to the previously set filter */}
<IconMenu.Item name="artists" to="/artists" label="Artists" icon={<PeopleIcon />} />
</IconMenu>
);
Then, create a custom layout using the <Layout>
component and pass your custom menu component to it. Make sure you wrap the layout with the <AppLocationContext>
component.
// in src/MyLayout.js
import { Layout } from 'react-admin';
import { AppLocationContext } from '@react-admin/ra-navigation';
import { MyMenu } from './MyMenu';
export const MyLayout = ({ children }) => (
<AppLocationContext>
<Layout menu={MyMenu}>
{children}
</Layout>
</AppLocationContext>
);
<AppLocationContext>
is necessary because ra-navigation
doesnβt use the URL to detect the current location. Instead, page components declare their location using a custom hook (useDefineAppLocation()
). This allows complex site maps, with multiple levels of nesting. Check the ra-navigation documentation to learn more about App Location.
Finally, pass this custom layout to the <Admin>
component. You should apply the theme provided by ra-navigation:
// in src/App.js
import { Admin, Resource } from "react-admin";
import { theme } from '@react-admin/ra-navigation';
import { MyLayout } from './MyLayout';
const App = () => (
<Admin
layout={MyLayout}
dataProvider={...}
theme={theme}
>
// ...
</Admin>
);
In order to adjust the size of the React-Admin <Sidebar>
component according to the categories, you should either apply the theme
provided by the @react-admin/ra-navigation
package (as above), or merge it in your own custom theme.
import merge from 'lodash/merge';
import { defaultTheme } from 'react-admin';
import { ThemeOptions } from '@react-admin/ra-navigation';
export const theme: ThemeOptions = merge({}, defaultTheme, {
sidebar: {
width: 96,
closedWidth: 48,
},
overrides: {
RaSidebar: {
fixed: {
zIndex: 1200,
},
},
},
});
Tip: With <IconMenu />
, labels may disappear when the sidebar is in reduced mode. This is because of the internal workings of react-admin. Thatβs why we recommend implementing your own <AppBar />
, and hiding the Hamburger Button. <IconMenu />
is thin enough not to interfere with the navigation anyway.
Props
Prop | Required | Type | Default | Description |
---|---|---|---|---|
children |
Optional | ReactNode |
- | The Menu Item Links to be rendered. |
sx |
Optional | SxProps |
- | Style overrides, powered by MUI System |
Additional props are passed down to the root <div>
component.
children
Pass <IconMenu.Item>
children to <IconMenu>
to define the main menu entries.
// in src/MyMenu.js
import { IconMenu } from "@react-admin/ra-navigation";
import DashboardIcon from '@mui/icons-material/Dashboard';
import MusicIcon from '@mui/icons-material/MusicNote';
import PeopleIcon from '@mui/icons-material/People';
const MyMenu = () => (
<IconMenu>
<IconMenu.Item name="dashboard" to="/" label="Dashboard" icon={<DashboardIcon />} />
<IconMenu.Item name="songs" to="/songs" label="Songs" icon={<MusicIcon />} />
<IconMenu.Item name="artists" to="/artists" label="Artists" icon={<PeopleIcon />} />
</IconMenu>
);
Check the <IconMenu.Item>
section for more information.
sx
: CSS API
Pass an sx
prop to customize the style of the main component and the underlying elements.
export const MyMenu = () => (
<IconMenu sx={{ marginTop: 0 }}>
// ...
</IconMenu>
);
To override the style of <IconMenu>
using the application-wide style overrides, use the RaMenuRoot
key.
<IconMenu.Item>
The <IconMenu.Item>
component displays a menu item with a label and an icon.
<IconMenu.Item
name="dashboard"
to="/"
label="Dashboard"
icon={<DashboardIcon />}
/>
It requires the following props:
name
: the name of the location to match. This is used to highlight the current location.to
: the location to link to.label
: The menu item label.icon
: the icon to display.
It accepts optional props:
children
: Content of a sliding panel displayed when the menu is clicked (see Adding sub menus below)sx
: Style overrides, powered by MUI System
Additional props are passed down to the underling Material UI <listItem>
component.
Adding Sub Menus
You can define the content of the sliding panel revealed when the user clicks on a menu by adding children to <IconMenu.Item>
. <IconMenu>
renders its children inside a Material UI <Card>
, so itβs common to wrap the content in <CardContent>
.
For instance, here is how to add a sub menu to the Artists menu with one entry for each artist category:
import {
IconMenu,
MenuItemList,
MenuItemNode,
} from "@react-admin/ra-navigation";
import DashboardIcon from '@mui/icons-material/Dashboard';
import MusicIcon from '@mui/icons-material/MusicNote';
import PeopleIcon from '@mui/icons-material/People';
const MyMenu = () => (
<IconMenu>
<IconMenu.Item name="dashboard" to="/" label="Dashboard" icon={<DashboardIcon />} />
<IconMenu.Item name="songs" to="/songs" label="Songs" icon={<MusicIcon />} />
<IconMenu.Item name="artists" to="/artists" label="Artists" icon={<PeopleIcon />}>
<CardContent>
{/* to get consistent spacing */}
<Typography variant="h3" gutterBottom>
Artist Categories
</Typography>
{/* Note that we must wrap our MenuItemNode components in a MenuItemList */}
<MenuItemList>
<MenuItemNode
name="artists.rock"
to={'/artists?filter={"type":"rock"}'}
label="Rock"
/>
<MenuItemNode
name="artists.jazz"
to={'/artists?filter={"type":"jazz"}'}
label="Jazz"
/>
<MenuItemNode
name="artists.classical"
to={'/artists?filter={"type":"classical"}'}
label="Rock"
/>
</MenuItemList>
</CardContent>
</IconMenu.Item>
</IconMenu>
);
Creating Menu Items For Resources
If you want to render a custom menu item and the default resource menu items, use the useResourceDefinitions
hook to retrieve the list of resources and create one menu item per resource.
// in src/MyMenu.js
import { createElement } from 'react';
import { useResourceDefinitions } from 'react-admin';
import { IconMenu } from "@react-admin/ra-navigation";
import LabelIcon from '@mui/icons-material/Label';
export const MyMenu = () => {
const resources = useResourceDefinitions();
return (
<IconMenu>
{Object.keys(resources).map(name => (
<IconMenu.Item
key={name}
name={name}
to={`/${name}`}
label={resources[name].options && resources[name].options.label || name}
icon={createElement(resources[name].icon)}
/>
))}
<IconMenu.Item name="custom.route" to="/custom-route" label="Miscellaneous" icon={<LabelIcon />} />
</IconMenu>
);
};