<Breadcrumb>

This Enterprise Edition component renders a breadcrumb path that automatically adapts to the page location. It helps users navigate large web applications.

Test it live on the Enterprise Edition demo.

The breadcrumb path can complement and/or replace navigation menus, back buttons, page titles, and site maps. It’s a small but effective navigation control.

React-admin’s <Breadcrumb> is not a pure UI component that you use in each page to manually render a breadcrumb path (for that, you can use Material-UI’s <Breadcrumbs>). It’s a smart component designed to be inserted in the application layout that renders the breadcrumb path of the current page. Breadcrumb items can be completely customized, and may include data from the current context (e.g. the name or title of the current record).

Usage

Create a custom layout component containing the <Breadcrumb> component. For example, using the default <Layout> component from react-admin:

// in src/MyLayout.jsx
import { AppLocationContext, Breadcrumb } from '@react-admin/ra-navigation';
import { Layout } from 'react-admin';

export const MyLayout = ({ children }) => (
    <AppLocationContext>
        <Layout>
            <Breadcrumb />
            {children}
        </Layout>
    </AppLocationContext>
);

Tip: The layout must be wrapped with <AppLocationContext>, as <Breadcrumb> reads the app location from this context and not the URL. Layout components from ra-navigation (<ContainerLayout> or <SolarLayout>) already include that context, so it’s not necessary to include it in the custom layout.

Tip: The ra-enterprise package exports an alternative <Layout>, which contains a pre-configured <Breadcrumb> that renders breadcrumb paths for all resources.

Next, set this custom layout as the <Admin layout> component:

import { Admin } from 'react-admin';
import { DataProvider } from './dataProvider';
import { MyLayout } from './MyLayout';

const App = () => (
    <Admin dataProvider={dataProvider} layout={MyLayout}>
        ...
    </Admin>
);

Now every CRUD page for the declared resources displays a breadcrumb path. For example, for the posts resource:

  • “Posts” on the Post List page
  • “Posts / #1” on the Post Edition page with id = 1
  • “Posts / #1” on the Post Show page with id = 1
  • “Posts / Create” on the Post Creation page

By default, <Breadcrumb> uses the id field to identify the current record on show and edit pages. You can customize it by setting the <Resource recordRepresentation> prop to a string or a function:

const App = () => {
    <Admin dataProvider={dataProvider} layout={MyLayout}>
        <Resource
            name="posts"
            recordRepresentation="title"
            list={PostList}
            edit={PostEdit}
            show={PostShow}
            create={PostCreate}
        />
        ...
    </Admin>
};

With this setup, the breadcrumb on the post pages will use the title field of the record:

  • “Posts” on the Post List page
  • “Posts / Lorem ipsum” on the Post Edition page with id = 1
  • “Posts / Lorem ipsum” on the Post Show page with id = 1
  • “Posts / Create” on the Post Creation page

The Breadcrumb component will automatically detect if your app has a home or dashboard page, thanks to react-admin’s useHasDashboard hook.

With a dashboard, the breadcrumb on the post pages now renders as:

  • “🏠️ / Posts” on the Post List page
  • “🏠️ / Posts / Lorem ipsum” on the Post Edition page with id = 1
  • “🏠️ / Posts / Lorem ipsum” on the Post Show page with id = 1
  • “🏠️ / Posts / Create” on the Post Creation page

You can customize the breadcrumb path of each page, as well as add custom pages to the breadcrumb, by adding children to the <Breadcrumb> component. See the children section below for more information.

App Location

<Breadcrumb> relies on the application location, which is distinct from the browser location. This distinction is important as it allows displaying a navigation UI independent of the URL (e.g. grouping resources under a common section, like “Catalog / Products” and “Catalog / Categories”, or nesting resources, like “Customers / John Doe / Orders / 1234”).

Each page in a react-admin application can define its app location using a custom hook called useDefineAppLocation. ra-navigation stores this location in the <AppLocationContext>. UI components like <Breadcrumb> use that context to display consistent navigation information.

You don’t need to define the app location for CRUD pages as react-admin does it by default:

  • List: [resource]
  • Create: [resource].create
  • Edit: [resource].edit. The location also contains the current record
  • Show: [resource].show. The location also contains the current record

However, you can customize these default app locations in your CRUD pages, and you must define the location for custom pages.

To leverage the provided components such as the <Breadcrumb> or <MultiLevelMenu>, the layout must be wrapped with <AppLocationContext>.

Layout components from ra-navigation (<ContainerLayout> or <SolarLayout>) already include that context, so you can skip that step if you are using one of these layouts.

If, however, you are using the default <Layout> component from react-admin, or a custom layout, you must wrap it with <AppLocationContext>:

import { AppLocationContext } from '@react-admin/ra-navigation';
import { Admin, Resource, Layout } from 'react-admin';

const MyLayout = ({ children }) => (
    <AppLocationContext>
        <Layout>
            {children}
        </Layout>
    </AppLocationContext>
);

const App = () => (
    <Admin dataProvider={dataProvider} layout={MyLayout}>
        <Resource name="posts" list={PostList} />
    </Admin>
);

Props

Prop Required Type Default Description
children Optional ReactNode - The Breadcrumb Items to be rendered.
separator Optional string or function ’ / ‘ The character user as separator
sx Optional SxProps - Style overrides, powered by MUI System

Additional props are passed down to the root <nav> component.

children

Use the <Breadcrumb> children prop to define how a given app location renders in the breadcrumb. Children of the <Breadcrumb> component must be <Breadcrumb.Item> components, or any of its derivatives (<Breadcrumb.ResourceItem>, <Breadcrumb.ResourceItems>). These components can themselves have children in order to create a breadcrumb path of any depth.

Every <Breadcrumb> child must have a name prop. This name corresponds to a segment of the app location. For example, for an app location catalog.categories.list, the <Breadcrumb> will display the child with the name prop set to catalog. If no child matches the current app location, the <Breadcrumb> won’t display anything.

For instance, Here’s how you can create a custom breadcrumb for two resources: posts and comments.

// in src/MyBreadcrumb.jsx
import { Breadcrumb } from '@react-admin/ra-navigation';

export const MyBreadcrumb = () => (
    <Breadcrumb>
        <Breadcrumb.Item name="posts" label="Posts" to="/posts">
            <Breadcrumb.Item
                name="edit"
                label={({ record }) => `Edit #${record.id}`}
                to={({ record }) => `/posts/${record.id}`}
            />
            <Breadcrumb.Item
                name="show"
                label={({ record }) => `Show #${record.id}`}
                to={({ record }) => `/posts/${record.id}/show`}
            />
            <Breadcrumb.Item name="create" label="Create" to="/posts/create" />
        </Breadcrumb.Item>
        <Breadcrumb.Item name="comments" label="Comments" to="/comments">
            <Breadcrumb.Item
                name="edit"
                label={({ record }) => `Edit #${record.id}`}
                to={({ record }) => `/comments/${record.id}`}
            />
            <Breadcrumb.Item
                name="show"
                label={({ record }) => `Show #${record.id}`}
                to={({ record }) => `/comments/${record.id}/show`}
            />
            <Breadcrumb.Item
                name="create"
                label="Create"
                to="/comments/create"
            />
        </Breadcrumb.Item>
    </Breadcrumb>
);

Replace the default <Breadcrumb> in your layout with your custom <MyBreadcrumb> component:

// in src/MyLayout.jsx
import { AppLocationContext, Breadcrumb } from '@react-admin/ra-navigation';
import { Layout } from 'react-admin';

import { MyBreadcrumb } from './MyBreadcrumb';

export const MyLayout = ({ children }) => (
    <AppLocationContext>
        <Layout>
            <MyBreadcrumb />
            {children}
        </Layout>
    </AppLocationContext>
);

The above breadcrumb setup will display:

  • “Posts” on the Post List page
  • “Posts / Show #1” on the Post Show page with id = 1
  • “Posts / Edit #1” on the Post Edition page with id = 1
  • “Posts / Create” on the Post Creation page
  • “Comments” on the Comment list page
  • “Comments / Show #1” on the Comment Show page with id = 1
  • “Comments / Edit #1” on the Comment Edition page with id = 1
  • “Comments / Create” on the Comment Creation page

As defining the paths for all the resources is a common use case, <Breadcrumb> provides a component that does the same. It’s called <Breadcrumb.ResourceItems>. So the following breadcrumb is equivalent to the previous one:

// in src/MyBreadcrumb.jsx
import { Breadcrumb } from '@react-admin/ra-navigation';

export const MyBreadcrumb = () => (
    <Breadcrumb>
        <Breadcrumb.ResourceItems />
    </Breadcrumb>
);

This means you can use the default breadcrumb for CRUD pages, and only define breadcrumb items for custom pages. For instance, to set up a breadcrumb for an app with a Settings page, you can do the following:

// in src/MyBreadcrumb.jsx
import { Breadcrumb } from '@react-admin/ra-navigation';

const MyBreadcrumb = () => (
    <Breadcrumb>
        <Breadcrumb.ResourceItems />
        <Breadcrumb.Item name="settings" label="Settings" to="/settings" />
    </Breadcrumb>
);

See the following sections for the detailed syntax of possible <Breadcrumb> children:

separator

The breadcrumb separator used by default is “ / “. You can override it by passing a string or a function as the separator prop.

Breadcrumb separator

// use a separator string
const MyBreadcrumb = () => (
    <Breadcrumb separator=" > ">
        ...
    </Breadcrumb>
);

// use a separator function to set the separator pseudo-content CSS
const MyBreadcrumb = () => (
    <Breadcrumb separator={() => `url('data:image/png;base64,iVBORw0KGgoAA....')`}>
        ...
    </Breadcrumb>
);

sx

You can override the style of the breadcrumb and its items using the sx prop.

const MyBreadcrumb = () => (
    <Breadcrumb
        sx={{
            '& ul': { padding: 1, paddingLeft: 0 },
            '& ul:empty': { padding: 0 },
        }}
    >
        // ...
    </Breadcrumb>
);

The <Breadcrumb.Item> component is responsible for rendering individual breadcrumb items. It displays the item when the app’s location matches the specified name. You can nest this component to create breadcrumb paths of varying depths.

A breadcrumb item

It requires the following props:

  • name: Represents the item’s name, which is used to determine its full path in the breadcrumb.
  • label: Specifies the display label for the item. Can be a string (including a translation key) or a function returning a string based on the location context.

It accepts the following optional props:

  • to: Defines the react-router path for the link. Can be a string, or a function that returns a string based on the location context.

Note: If the to prop is provided, <Breadcrumb.Item> will render as a link. Without it, the component will render as a <span>.

Here is an example breadcrumb rendering the CRUD path for a posts resource:

import { Breadcrumb } from '@react-admin/ra-navigation';

const MyBreadcrumb = () => (
    <Breadcrumb>
        <Breadcrumb.Item name="posts" label="Posts">
            <Breadcrumb.Item
                name="edit"
                label={({ record }) => `Edit "${record.title}"`}
                to={({ record }) => `/posts/${record.id}`}
            />
            <Breadcrumb.Item
                name="show"
                label={({ record }) => record.title}
                to={({ record }) => `/posts/${record.id}/show`}
            />
            <Breadcrumb.Item name="list" label="My Post List" />
            <Breadcrumb.Item name="create" label="Let's write a Post!" />
        </Breadcrumb.Item>
    </Breadcrumb>
);

Here is another example, showing how to use a React component as label:

import { Breadcrumb } from '@react-admin/ra-navigation';
import { Typography, Stack } from '@mui/material';
import NewspaperIcon from '@mui/icons-material/Newspaper';

const IconAndLabel = ({
    label,
    icon,
}: {
    label: string;
    icon: React.ReactNode;
}) => (
    <Stack direction="row" alignItems="center" spacing={1}>
        {icon}
        <Typography variant="body2">{label}</Typography>
    </Stack>
);

const MyBreadcrumb = () => (
    <Breadcrumb>
        <Breadcrumb.Item 
            name="posts"
            label={
                <IconAndLabel
                    label="My Fabulous Posts"
                    icon={<NewspaperIcon />}
                />
            }
        >
            <Breadcrumb.Item
                name="edit"
                label={({ record }) => `Edit "${record.title}"`}
                to={({ record }) => `/posts/${record.id}`}
            />
            <Breadcrumb.Item
                name="show"
                label={({ record }) => record.title}
                to={({ record }) => `/posts/${record.id}/show`}
            />
            <Breadcrumb.Item name="create" label="Let's write a Post!" />
        </Breadcrumb.Item>
    </Breadcrumb>
);

<Breadcrumb> contains shortcut components for defining several <Breadcrumb.Item> children in a row: <Breadcrumb.ResourceItem>and <Breadcrumb.ResourceItems>.

This component renders the 4 breadcrumb items for the CRUD routes of a given resource. It only takes the resource name and relies on the label prop defined in the <Resource options> for the label.

import { Breadcrumb } from '@react-admin/ra-navigation';

const MyBreadcrumb = () => (
    <Breadcrumb>
        <Breadcrumb.ResourceItem resource="posts" />
        <Breadcrumb.ResourceItem resource="comments" />
    </Breadcrumb>
);

is equivalent to:

// in src/MyBreadcrumb.jsx
import { Breadcrumb } from '@react-admin/ra-navigation';

export const MyBreadcrumb = () => (
    <Breadcrumb>
        <Breadcrumb.Item name="posts" label="Posts" to="/posts">
            <Breadcrumb.Item
                name="edit"
                label={({ record }) => `#${record.id}`}
                to={({ record }) => `/posts/${record.id}`}
            />
            <Breadcrumb.Item
                name="show"
                label={({ record }) => `#${record.id}`}
                to={({ record }) => `/posts/${record.id}/show`}
            />
            <Breadcrumb.Item name="create" label="Create" to="/posts/create" />
        </Breadcrumb.Item>
        <Breadcrumb.Item name="comments" label="Comments" to="/comments">
            <Breadcrumb.Item
                name="edit"
                label={({ record }) => `#${record.id}`}
                to={({ record }) => `/comments/${record.id}`}
            />
            <Breadcrumb.Item
                name="show"
                label={({ record }) => `#${record.id}`}
                to={({ record }) => `/comments/${record.id}/show`}
            />
            <Breadcrumb.Item
                name="create"
                label="Create"
                to="/comments/create"
            />
        </Breadcrumb.Item>
    </Breadcrumb>
);

Tip: If you need more fine-grained control over the labels, you can override the Resource Breadcrumb items.

This component renders one <Breadcrumb.ResourceItem> for each of the <Resource> declared in the admin.

import { Breadcrumb } from '@react-admin/ra-navigation';

const MyBreadcrumb = () => (
    <Breadcrumb>
        <Breadcrumb.ResourceItems />
    </Breadcrumb>
);

Given the following app:

const App = () => (
    <Admin dataProvider={dataProvider} layout={MyLayout}>
        <Resource name="posts" list={PostList} />
        <Resource name="comments" list={CommentList} />
        <Resource name="tags" list={TagList} />
    </Admin>
);

The <Breadcrumb.ResourceItems> is equivalent to:

const MyBreadcrumb = () => (
    <Breadcrumb>
        <Breadcrumb.ResourceItem resource="posts" />
        <Breadcrumb.ResourceItem resource="comments" />
        <Breadcrumb.ResourceItem resource="tags" />
    </Breadcrumb>
);

This component can render <Breadcrumb.ResourceItem> for only a subset of resources defined in the resources prop.

const MyBreadcrumb = () => (
    <Breadcrumb>
        <Breadcrumb.ResourceItems resources={['posts', 'comments']} />
    </Breadcrumb>
);

This is equivalent to:

const MyBreadcrumb = () => (
    <Breadcrumb>
        <Breadcrumb.ResourceItem resource="posts" />
        <Breadcrumb.ResourceItem resource="comments" />
    </Breadcrumb>
);

Check the <Breadcrumb.ResourceItem> section for more information.

A version of the <Breadcrumb.Item> dedicated to the dashboard.

It is convenient for customizing the dashboard item label.

const MyBreadcrumbCustomHome = () => (
    <Breadcrumb>
        <Breadcrumb.DashboardItem label="My Home">
            <Breadcrumb.ResourceItem resource="posts" />
            <Breadcrumb.ResourceItem resource="comments" />
        </Breadcrumb.DashboardItem>
    </Breadcrumb>
);

Just like with <Breadcrumb.Item>, you can also use a React component as label:

import { Breadcrumb } from '@react-admin/ra-navigation';
import { Box, Stack } from '@mui/material';
import { visuallyHidden } from '@mui/utils';
import CabinIcon from '@mui/icons-material/Cabin';

const MyBreadcrumbCustomHome = () => (
    <Breadcrumb>
        <Breadcrumb.DashboardItem
            label={
                <Stack direction="row" alignItems="center" spacing={1}>
                    <CabinIcon />
                    <Box sx={visuallyHidden}>Dashboard</Box>
                </Stack>
            }
        >
            <Breadcrumb.ResourceItem resource="posts" />
            <Breadcrumb.ResourceItem resource="comments" />
        </Breadcrumb.DashboardItem>
    </Breadcrumb>
);

Tip: It’s a good practice to include a visually hidden placeholder (‘Dashboard’ in this example) for screen readers when using an icon as label.

Admins With A Dashboard

If the app has a home page defined via the <Admin dashboard> prop, the Breadcrumb will automatically detect it and set the root of the Breadcrumb to this page.

The breadcrumb will show respectively:

  • “🏠️ / Posts” on the Post List page
  • “🏠️ / Posts / Show #1” on the Post Show page with id = 1
  • “🏠️ / Posts / Edit #1” on the Post Edition page with id = 1
  • “🏠️ / Posts / Create” on the Post Creation page

Tip: Even though it is rendered as a ‘home’ icon (🏠️), the dashboard breadcrumb item also contains the hidden placeholder text ‘Dashboard’, for screen readers. If you want to customize this text, e.g. to rename “Dashboard” to “Home”, provide a custom translation for the ra.page.dashboard message.

If you want to provide your own label for the dashboard breadcrumb item (either a string or a React component), you can use the <Breadcrumb.DashboardItem> component.

Adding Custom Pages

A page component can define its app location using the useDefineAppLocation hook:

// in src/UserPreferences.jsx
import { useDefineAppLocation } from '@react-admin/ra-navigation';

const UserPreferences = () => {
    useDefineAppLocation('user.preferences');
    return <span>My Preferences</span>;
};

Let’s say that this custom page is added to the app under the /settings URL:

// in src/App.jsx
import { Admin, Resource, CustomRoutes, } from 'react-admin';
import { Route } from 'react-router-dom';

import { MyLayout } from './MyLayout';
import { UserPreferences } from './UserPreferences';

const App = () => (
    <Admin dataProvider={dataProvider} layout={MyLayout}>
        ...
        <CustomRoutes>
            <Route exact path="/settings" component={UserPreferences} />,
        </CustomRoutes>
    </Admin>
);

It’s the job of the <Breadcrumb> component to define the breadcrumb path for this page location using its children:

// in src/MyBreadcrumb.jsx
import { Breadcrumb } from '@react-admin/ra-navigation';

export const MyBreadcrumb = () => (
    <Breadcrumb>
        <Breadcrumb.ResourceItems />
        <Breadcrumb.Item name="user" label="User">
            <Breadcrumb.Item name="preferences" label="Preferences" to="/settings" />
        </Breadcrumb.Item>
    </Breadcrumb>
);

Finally, don’t forget to use the <MyBreadcrumb> component in the layout:

// in src/MyLayout.jsx
import { AppLocationContext, Breadcrumb } from '@react-admin/ra-navigation';
import { Layout } from 'react-admin';

import { MyBreadcrumb } from './MyBreadcrumb';

export const MyLayout = ({ children }) => (
    <AppLocationContext>
        <Layout>
            <MyBreadcrumb />
            {children}
        </Layout>
    </AppLocationContext>
);

Overriding Items For One Resource

In some cases, it’s useful to override the default resource breadcrumb path, e.g. to add a custom label instead of “Show #1”, “Edit #1”, etc. If the <Resource recordRepresentation> is not enough, you can disable the concerned resources in the <Breadcrumb.ResourceItems resources> prop, and declare the breadcrumb items for these resources manually.

import React from 'react';
import { AppLocationContext, Breadcrumb } from '@react-admin/ra-navigation';
import { Admin, Resource, Layout, useCreatePath, List } from 'react-admin';

const MyBreadcrumb = () => {
    const createPath = useCreatePath();

    return (
        <Breadcrumb>
            {/* no Breadcrumb.ResourceItem for the 'posts' resource */}
            <Breadcrumb.ResourceItems resources={['comments', 'tags']} />
            {/* we define it manually */}
            <Breadcrumb.Item name="posts" label="Posts">
                <Breadcrumb.Item
                    name="edit"
                    label={({ record }) => `Edit "${record.title}"`}
                    to={({ record }) => `/posts/${record.id}`}
                />
                <Breadcrumb.Item
                    name="show"
                    label={({ record }) => record.title}
                    to={({ record }) => `/posts/${record.id}/show`}
                />
                <Breadcrumb.Item name="create" label="Create" to="/posts/create" />
            </Breadcrumb.Item>
        </Breadcrumb>
    );
};

const MyLayout = ({ children }) => (
    <AppLocationContext>
        <Layout>
            <MyBreadcrumb />
            {children}
        </Layout>
    </AppLocationContext>
);

const App = () => (
    <Admin dataProvider={dataProvider} layout={MyLayout}>
        <Resource name="posts" list={PostList} />
        <Resource name="comments" list={CommentList} />
        <Resource name="tags" list={TagList} />
    </Admin>
);

Nested Resources

When using nested resources, you should create breadcrumb items for the sub-resources.

For instance, the screencast at the top of this page shows a songs resource nested in an artists resource, using the following routes:

import { Admin, Resource } from 'react-admin';
import { Route } from 'react-router-dom';

export const App = () => (
    <Admin dataProvider={dataProvider}>
        <Resource name="artists" list={ArtistList} edit={ArtistDetail}>
            <Route path=":id/songs" element={<SongList />} />
            <Route path=":id/songs/:songId" element={<SongDetail />} />
        </Resource>
    </Admin>
);

This setup creates four routes:

  • /artists renders the <ArtistList> element
  • /artists/:id renders the <ArtistDetail> element
  • /artists/:id/songs renders the <SongList> element
  • /artists/:id/songs/:songId renders the <SongDetail> element

One app location is defined for each route:

  • /artists: artists (defined automatically)
  • /artists/:id: artists.edit (defined automatically)
  • /artists/:id/songs: artists.edit.songs (defined manually)
  • /artists/:id/songs/:songId: artists.edit.songs.edit (defined manually)

Let’s see how the components for the songs list and detail pages define their app location:

// in src/songs/SongList.js
import { useGetOne, List, SearchInput, Datagrid, TextField, DateField } from 'react-admin';
import { useDefineAppLocation } from '@react-admin/ra-navigation';
import { useParams } from 'react-router-dom';

export const SongList = () => {
    const { id } = useParams();
    const { data: record } = useGetOne('artists', { id });
    useDefineAppLocation('artists.edit.songs', { record });
    return (
        <List
            resource="songs"
            filter={{ artist_id: id }}
            filters={[<SearchInput key="q" source="q" alwaysOn />]}
        >
            <Datagrid>
                <TextField source="title" />
                <DateField source="released" />
                <TextField source="writer" />
                <TextField source="producer" />
                <TextField source="recordCompany" label="Label" />
                <EditSongButton />
            </Datagrid>
        </List>
    );
};

const EditSongButton = () => {
    const song = useRecordContext();
    return (
        <Button
            component={Link}
            to={`/artists/${song?.artist_id}/songs/${song?.id}`}
            startIcon={<EditIcon />}
        >
            Edit
        </Button>
    );
};
// in src/songs/SongDetail.js
import { useGetOne, Edit, SimpleForm, TextInput, DateInput } from 'react-admin';
import { useDefineAppLocation } from '@react-admin/ra-navigation';
import { useParams } from 'react-router-dom';

export const SongDetail = () => {
    const { id, songId } = useParams();
    const { data: record } = useGetOne('artists', { id });
    const { data: song } = useGetOne('songs', { id: songId });
    useDefineAppLocation('artists.edit.songs.edit', { record, song });
    return (
        <Edit resource="songs" id={songId} redirect={`/artists/${id}/songs`}>
            <SimpleForm>
                <TextInput source="title" />
                <DateInput source="released" />
                <TextInput source="writer" />
                <TextInput source="producer" />
                <TextInput source="recordCompany" label="Label" />
            </SimpleForm>
        </Edit>
    );
};

Tip: The <Edit> component will call dataProvider.getOne("songs", { id: songId }) to fetch the song record. Since the <SongDetail> component makes the same request, React-admin will deduplicate the calls and only make one request to the dataProvider.

Tip: You don’t need to call useDefineAppLocation for the pages of the parent resource (artists) as this resource uses the default URLs (/artists, /artists/:id). The app location will be deduced automatically from these URLs (i.e. artists and artists.edit).

Once the app locations are properly set up, the Breadcrumb code comes naturally as:

const MyBreadcrumb = () => (
    <Breadcrumb>
        <Breadcrumb.Item name="artists" label="Artists" to="/artists">
            <Breadcrumb.Item
                name="edit"
                label={({ record }) => record?.name}
                to={({ record }) => `/artists/${record?.id}`}
            >
                <Breadcrumb.Item
                    name="songs"
                    label="Songs"
                    to={({ record }) => `/artists/${record?.id}/songs`}
                >
                    <Breadcrumb.Item
                        name="edit"
                        label={({ song }) => song?.title}
                        to={({ song }) => `/artists/${song?.artist_id}/songs/${song?.id}`}
                    />
                </Breadcrumb.Item>
            </Breadcrumb.Item>
            <Breadcrumb.Item
                name="create"
                label="Create"
                to="/artists/create"
            />
        </Breadcrumb.Item>
    </Breadcrumb>
);

Grouping Resources

You may want to group CRUD pages for several resources under a common parent item. For instance, let’s say that the pages for the songs and artists resources have to be grouped under a “Music” item. The breadcrumb path for the list pages of these resources should look like the following:

  • “Music / Songs” on the Song List page
  • “Music / Artists” on the Artist List page

To do so, override the app location of the CRUD pages using the useDefineAppLocation hook. Here is an example for the songs resource:

// in src/songs/SongList.jsx
import { List, Datagrid, TextField } from 'react-admin';
import { useDefineAppLocation } from '@react-admin/ra-navigation';

export const SongList = () => {
    useDefineAppLocation('music.songs');
    return (
        <List>
            <Datagrid>
                <TextField source="title" />
            </Datagrid>
        </List>
    );
};

// in src/songs/SongEdit.jsx
import { Edit, SimpleForm, TextInput, useRecordContext } from 'react-admin';
import { useDefineAppLocation } from '@react-admin/ra-navigation';

const SongEditAppLocation = () => {
    const record = useRecordContext();
    useDefineAppLocation('music.songs.edit', { record });
    return null;
};

export const SongEdit = () => (
    <Edit>
        <SongEditAppLocation />
        <SimpleForm>
            <TextInput source="title" />
        </SimpleForm>
    </Edit>
);

// in src/songs/SongShow.jsx
import { Show, SimpleShowLayout, TextField, useRecordContext } from 'react-admin';
import { useDefineAppLocation } from '@react-admin/ra-navigation';

const SongShowAppLocation = () => {
    const record = useRecordContext();
    useDefineAppLocation('music.songs.show', { record });
    return null;
};

export const SongShow = () => (
    <Show>
        <SongShowAppLocation />
        <SimpleShowLayout>
            <TextField source="title" />
        </SimpleShowLayout>
    </Show>
);

// in src/songs/SongCreate.jsx
import { Create, SimpleForm, TextInput } from 'react-admin';
import { useDefineAppLocation } from '@react-admin/ra-navigation';

export const SongCreate = () => {
    useDefineAppLocation('music.songs.create');
    return (
        <Create>
            <SimpleForm>
                <TextInput source="title" />
            </SimpleForm>
        </Create>
    );
};

Then, in the breadcrumb, nest <Breadcrumb.ResourceItem> elements for the songs and artists resources under a parent <Breadcrumb.Item name="music">:

const MyBreadcrumb = () => (
    <Breadcrumb>
        <Breadcrumb.Item name="music" label="Music">
            <Breadcrumb.ResourceItem resource="songs" />
            <Breadcrumb.ResourceItem resource="artists" />
        </Breadcrumb.Item>
    </Breadcrumb>
);

As you see, you can compose Breadcrumb item elements at will.