A breadcrumbs is a list of links that help visualize a page's location within a site's hierarchical structure, it allows navigation up to any of the ancestors.
{{ādemoā: āBasicBreadcrumbs.jsā}}
Keep the last breadcrumb interactive.
{{ādemoā: āActiveLastBreadcrumb.jsā}}
In the following examples, we are using two string separators and an SVG icon.
{{ādemoā: āCustomSeparator.jsā}}
{{ādemoā: āIconBreadcrumbs.jsā}}
{{ādemoā: āCollapsedBreadcrumbs.jsā}}
As an alternative, consider adding a Menu component to display the condensed links in a dropdown list:
{{ādemoā: āCondensedWithMenu.jsā}}
Here is an example of customizing the component. You can learn more about this in the overrides documentation page.
{{ādemoā: āCustomizedBreadcrumbs.jsā}}
import * as React from 'react';
import Box from '@mui/material/Box';
import List from '@mui/material/List';
import Link, { LinkProps } from '@mui/material/Link';
import { ListItemProps } from '@mui/material/ListItem';
import ListItemButton from '@mui/material/ListItemButton';
import Collapse from '@mui/material/Collapse';
import ListItemText from '@mui/material/ListItemText';
import Typography from '@mui/material/Typography';
import ExpandLess from '@mui/icons-material/ExpandLess';
import ExpandMore from '@mui/icons-material/ExpandMore';
import Breadcrumbs from '@mui/material/Breadcrumbs';
import {
Link as RouterLink,
Route,
Routes,
MemoryRouter,
useLocation,
} from 'react-router';
interface ListItemLinkProps extends ListItemProps {
to: string;
open?: boolean;
}
const breadcrumbNameMap: { [key: string]: string } = {
'/inbox': 'Inbox',
'/inbox/important': 'Important',
'/trash': 'Trash',
'/spam': 'Spam',
'/drafts': 'Drafts',
};
function ListItemLink(props: ListItemLinkProps) {
const { to, open, ...other } = props;
const primary = breadcrumbNameMap[to];
let icon = null;
if (open != null) {
icon = open ? <ExpandLess /> : <ExpandMore />;
}
return (
<li>
<ListItemButton component={RouterLink as any} to={to} {...other}>
<ListItemText primary={primary} />
{icon}
</ListItemButton>
</li>
);
}
interface LinkRouterProps extends LinkProps {
to: string;
replace?: boolean;
}
function LinkRouter(props: LinkRouterProps) {
return <Link {...props} component={RouterLink as any} />;
}
function Page() {
const location = useLocation();
const pathnames = location.pathname.split('/').filter((x) => x);
return (
<Breadcrumbs aria-label="breadcrumb">
<LinkRouter underline="hover" color="inherit" to="/">
Home
</LinkRouter>
{pathnames.map((value, index) => {
const last = index === pathnames.length - 1;
const to = `/${pathnames.slice(0, index + 1).join('/')}`;
return last ? (
<Typography key={to} sx={{ color: 'text.primary' }}>
{breadcrumbNameMap[to]}
</Typography>
) : (
<LinkRouter underline="hover" color="inherit" to={to} key={to}>
{breadcrumbNameMap[to]}
</LinkRouter>
);
})}
</Breadcrumbs>
);
}
export default function RouterBreadcrumbs() {
const [open, setOpen] = React.useState(true);
const handleClick = () => {
setOpen((prevOpen) => !prevOpen);
};
return (
<MemoryRouter initialEntries={['/inbox']} initialIndex={0}>
<Box sx={{ display: 'flex', flexDirection: 'column', width: 360 }}>
<Routes>
<Route path="*" element={<Page />} />
</Routes>
<Box
sx={{ bgcolor: 'background.paper', mt: 1 }}
component="nav"
aria-label="mailbox folders"
>
<List>
<ListItemLink to="/inbox" open={open} onClick={handleClick} />
<Collapse component="li" in={open} timeout="auto" unmountOnExit>
<List disablePadding>
<ListItemLink sx={{ pl: 4 }} to="/inbox/important" />
</List>
</Collapse>
<ListItemLink to="/trash" />
<ListItemLink to="/spam" />
</List>
</Box>
</Box>
</MemoryRouter>
);
}
(WAI-ARIA: https://www.w3.org/WAI/ARIA/apg/patterns/breadcrumb/)
Be sure to add a aria-label
description on the Breadcrumbs
component.
The accessibility of this component relies on:
<ol>
element).aria-hidden
.aria-label
identifies the structure as a breadcrumb trail and makes it a navigation landmark so that it is easy to locate.The PageContainer component in @toolpad/core
is the ideal wrapper for the content of your dashboard. It makes the MaterialĀ UI Container navigation-aware and extends it with page title, breadcrumbs, actions, and more.
import * as React from 'react';
import { styled, useTheme } from '@mui/material/styles';
import DashboardIcon from '@mui/icons-material/Dashboard';
import { AppProvider, Navigation, Router } from '@toolpad/core/AppProvider';
import { PageContainer, PageContainerToolbar } from '@toolpad/core/PageContainer';
import Grid from '@mui/material/Grid2';
import Paper from '@mui/material/Paper';
import Stack from '@mui/material/Stack';
import Button from '@mui/material/Button';
import PrintIcon from '@mui/icons-material/Print';
import DownloadIcon from '@mui/icons-material/Download';
const NAVIGATION: Navigation = [
{
segment: 'orders',
title: 'Orders',
icon: <DashboardIcon />,
},
];
function useDemoRouter(initialPath: string): Router {
const [pathname, setPathname] = React.useState(initialPath);
const router = React.useMemo(() => {
return {
pathname,
searchParams: new URLSearchParams(),
navigate: (path: string | URL) => setPathname(String(path)),
};
}, [pathname]);
return router;
}
const Skeleton = styled('div')<{ height: number }>(({ theme, height }) => ({
backgroundColor: theme.palette.action.hover,
borderRadius: theme.shape.borderRadius,
height,
content: '" "',
}));
function PageToolbar() {
return (
<PageContainerToolbar>
<Stack direction="row" spacing={1} alignItems="center">
<Button
variant="outlined"
size="small"
color="neutral"
startIcon={<DownloadIcon fontSize="inherit" />}
>
Download
</Button>
<Button
variant="outlined"
size="small"
color="neutral"
startIcon={<PrintIcon fontSize="inherit" />}
>
Print
</Button>
</Stack>
</PageContainerToolbar>
);
}
export default function PageContainerBasic(props: any) {
const { window } = props;
const router = useDemoRouter('/orders');
const theme = useTheme();
// Remove this const when copying and pasting into your project.
const demoWindow = window ? window() : undefined;
return (
<AppProvider
navigation={NAVIGATION}
router={router}
theme={theme}
window={demoWindow}
branding={{
title: 'ACME Inc.',
}}
>
<Paper sx={{ p: 2, width: '100%' }}>
<PageContainer
slots={{
toolbar: PageToolbar,
}}
>
<Grid container spacing={1}>
<Grid size={5} />
<Grid size={12}>
<Skeleton height={14} />
</Grid>
<Grid size={12}>
<Skeleton height={14} />
</Grid>
<Grid size={4}>
<Skeleton height={100} />
</Grid>
<Grid size={8}>
<Skeleton height={100} />
</Grid>
</Grid>
</PageContainer>
</Paper>
</AppProvider>
);
}