Skip to content

<ShowBase>

<ShowBase> fetches the record from the data provider via dataProvider.getOne(), puts it in a ShowContext, and renders its child. Use it to build a custom show page layout.

As a headless component, it does not render any layout by default.

<ShowBase> relies on the useShowController hook.

Use <ShowBase> instead of <Show> when you want a completely custom page layout, without the default actions and title.

// in src/posts.jsx
import * as React from "react";
import { ShowBase } from 'ra-core';
const PostShow = () => (
<ShowBase resource="posts">
<div style={{ display: 'flex' }}>
<div style={{ flex: 2 }}>
<div>
...
</div>
</div>
<div style={{ flex: 1 }}>
Show instructions...
</div>
</div>
<div>
Post related links...
</div>
</ShowBase>
);

Components using <ShowBase> can be used as the show prop of a <Resource> component:

// in src/App.jsx
import { CoreAdmin, Resource } from 'ra-core';
import { dataProvider } from './dataProvider';
import { PostShow } from './posts';
const App = () => (
<CoreAdmin dataProvider={dataProvider}>
<Resource name="posts" show={PostShow} />
</CoreAdmin>
);

Tip: See useShowController for a completely headless version of this component.

PropRequiredTypeDefaultDescription
childrenOptionalReactNodeThe components rendering the record fields
renderOptional(props: ShowControllerResult<RecordType>) => ReactNodeAlternative to children, a function that takes the ShowController context and renders the form
disable AuthenticationOptionalbooleanSet to true to disable the authentication check
idOptionalstringThe record identifier. If not provided, it will be deduced from the URL
loadingOptionalReactNodeThe component to render while checking for authentication and permissions
offlineOptionalReactNodeThe component to render when there is no connectivity and the record isn’t in the cache
queryOptionsOptionalobjectThe options to pass to the useQuery hook
resourceOptionalstringThe resource name, e.g. posts

<ShowBase> renders its children wrapped by a RecordContext, so you can use any component that depends on such a context to be defined.

For instance, to display several fields in a grid layout:

import { ShowBase, ReferenceFieldBase, WithRecord } from 'ra-core';
import { TextField } from './TextField';
import { DateField } from './DateField';
const BookShow = () => (
<ShowBase>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: '1rem', margin: '1rem' }}>
<div>
<TextField label="Title" source="title" />
</div>
<div>
<ReferenceFieldBase label="Author" source="author_id" reference="authors">
<TextField source="name" />
</ReferenceFieldBase>
</div>
<div>
<DateField label="Publication Date" source="published_at" />
</div>
<div>
<WithRecord render={record => (
<span>
{record.rating >= 1 ? '⭐' : '☆'}
{record.rating >= 2 ? '⭐' : '☆'}
{record.rating >= 3 ? '⭐' : '☆'}
{record.rating >= 4 ? '⭐' : '☆'}
{record.rating >= 5 ? '⭐' : '☆'}
</span>
)} />
</div>
</div>
</ShowBase>
);

By default, the <ShowBase> component will automatically redirect the user to the login page if the user is not authenticated. If you want to disable this behavior and allow anonymous access to a show page, set the disableAuthentication prop to true.

import { ShowBase } from 'ra-core';
const PostShow = () => (
<ShowBase disableAuthentication>
...
</ShowBase>
);

By default, <ShowBase> deduces the identifier of the record to show from the URL path. So under the /posts/123/show path, the id prop will be 123. You may want to force a different identifier. In this case, pass a custom id prop.

import { ShowBase } from 'ra-core';
export const PostShow = () => (
<ShowBase id="123">
...
</ShowBase>
);

Tip: Pass both a custom id and a custom resource prop to use <ShowBase> independently of the current URL. This even allows you to use more than one <ShowBase> component in the same page.

By default, <ShowBase> renders nothing while checking for authentication and permissions. You can provide your own component via the loading prop:

import { ShowBase } from 'ra-core';
export const PostShow = () => (
<ShowBase loading={<p>Checking for permissions...</p>}>
...
</ShowBase>
);

By default, <ShowBase> renders nothing when there is no connectivity and the record hasn’t been cached yet. You can provide your own component via the offline prop:

import { ShowBase } from 'ra-core';
export const PostShow = () => (
<ShowBase offline={<p>No network. Could not load the post.</p>}>
...
</ShowBase>
);

Tip: If the record is in the Tanstack Query cache but you want to warn the user that they may see an outdated version, you can use the <IsOffline> component:

import { ShowBase, IsOffline } from 'ra-core';
export const PostShow = () => (
<ShowBase offline={<p>No network. Could not load the post.</p>}>
<IsOffline>
No network. The post data may be outdated.
</IsOffline>
...
</ShowBase>
);

<ShowBase> accepts a queryOptions prop to pass options to the react-query client.

This can be useful e.g. to override the default error side effect. By default, when the dataProvider.getOne() call fails at the dataProvider level, ra-core shows an error notification and refreshes the page.

You can override this behavior and pass custom side effects by providing a custom queryOptions prop:

import * as React from 'react';
import { useNotify, useRefresh, useRedirect, ShowBase } from 'ra-core';
const PostShow = () => {
const notify = useNotify();
const refresh = useRefresh();
const redirect = useRedirect();
const onError = (error) => {
notify(`Could not load post: ${error.message}`, { type: 'error' });
redirect('/posts');
refresh();
};
return (
<ShowBase queryOptions={{ onError }}>
...
</ShowBase>
);
}

The onError function receives the error from the dataProvider call (dataProvider.getOne()), which is a JavaScript Error object (see the dataProvider documentation for details).

The default onError function is:

(error) => {
notify('ra.notification.item_doesnt_exist', { type: 'error' });
redirect('list', resource);
refresh();
}

Alternatively, you can pass a render function prop instead of children. This function will receive the ShowContext as argument.

import { ShowBase } from 'ra-core';
const BookShow = () => (
<ShowBase render={({ isPending, error, record }) => {
if (isPending) {
return <p>Loading...</p>;
}
if (error) {
return (
<p className="error">
{error.message}
</p>
);
}
return <p>{record.title}</p>;
}}/>
);

By default, <ShowBase> operates on the current ResourceContext (defined at the routing level), so under the /posts/1/show path, the resource prop will be posts. You may want to force a different resource. In this case, pass a custom resource prop, and it will override the ResourceContext value.

import { ShowBase } from 'ra-core';
export const UsersShow = () => (
<ShowBase resource="users">
...
</ShowBase>
);

Tip: Pass both a custom id and a custom resource prop to use <ShowBase> independently of the current URL. This even allows you to use more than one <ShowBase> component in the same page.

The <ShowBase> component requires authentication and will redirect anonymous users to the login page. If you want to allow anonymous access, use the disableAuthentication prop.

If your authProvider implements Access Control, <ShowBase> will only render if the user has the “show” access to the related resource.

For instance, for the <PostShow>page below:

import { ShowBase } from 'ra-core';
import { TextField } from './TextField';
// Resource name is "posts"
const PostShow = () => (
<ShowBase>
<TextField source="title" />
<TextField source="author" />
<TextField source="published_at" />
</ShowBase>
);

<ShowBase> will call authProvider.canAccess() using the following parameters:

{ action: "show", resource: "posts" }

Users without access will be redirected to the Access Denied page.

Note: Access control is disabled when you use the disableAuthentication prop.