399 lines
19 KiB
Plaintext
399 lines
19 KiB
Plaintext
---
|
|
title: Swap in your own React components
|
|
label: Custom Components
|
|
order: 20
|
|
desc: Fully customize your Admin Panel by swapping in your own React components. Add fields, remove views, update routes and change functions to sculpt your perfect Dashboard.
|
|
keywords: admin, components, custom, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
|
|
---
|
|
|
|
The [Payload Admin Panel](./overview) is designed to be as minimal and straightforward as possible to allow for both easy customization and full control over the UI. In order for Payload to support this level of customization, Payload provides a pattern for you to supply your own React components through your [Payload Config](../configuration/overview).
|
|
|
|
All Custom Components in Payload are [React Server Components](https://react.dev/reference/rsc/server-components) by default, with the exception of [Custom Providers](#custom-providers). This enables the use of the [Local API](../local-api) directly in the front-end. Custom Components are available for nearly every part of the Admin Panel for extreme granularity and control.
|
|
|
|
<Banner type="success">
|
|
<strong>Note:</strong>
|
|
Client Components continue to be fully supported. To use Client Components in your app, simply include the `use client` directive. Payload will automatically detect and remove all default [non-serializable props](https://react.dev/reference/rsc/use-client#serializable-types) before rendering your component. [More details](#client-components).
|
|
</Banner>
|
|
|
|
To swap in your own Custom Component, consult the list of available components below. Determine the scope that corresponds to what you are trying to accomplish, then [author your React component(s)](#building-custom-components) accordingly.
|
|
|
|
There are four main types of Custom Components in Payload:
|
|
|
|
- [Root Components](#custom-root-components)
|
|
- [Collection Components](#custom-collection-components)
|
|
- [Global Components](#custom-global-components)
|
|
- [Field Components](./fields)
|
|
|
|
## Custom Root Components
|
|
|
|
Root Components are those that effect the [Admin Panel](./overview) generally, such as the logo. You can override Root Components through the `admin.components` property of the [Payload Config](../getting-started/overview).
|
|
|
|
Here is an example showing what it might look like to swap out Root Components for your own. See [Building Custom Components](#building-custom-components) for exact details on how to build them:
|
|
|
|
```ts
|
|
import { buildConfig } from 'payload'
|
|
|
|
import { MyCustomLogo } from './MyCustomLogo'
|
|
|
|
export default buildConfig({
|
|
// ...
|
|
admin: {
|
|
components: {
|
|
graphics: {
|
|
Logo: MyCustomLogo, // highlight-line
|
|
},
|
|
},
|
|
},
|
|
})
|
|
```
|
|
|
|
The following options are available:
|
|
|
|
| Path | Description |
|
|
|-----------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
| **`Nav`** | Contains the sidebar / mobile menu in its entirety. |
|
|
| **`BeforeNavLinks`** | An array of Custom Components to inject into the built-in Nav, _before_ the links themselves. |
|
|
| **`AfterNavLinks`** | An array of Custom Components to inject into the built-in Nav, _after_ the links. |
|
|
| **`BeforeDashboard`** | An array of Custom Components to inject into the built-in Dashboard, _before_ the default dashboard contents. |
|
|
| **`AfterDashboard`** | An array of Custom Components to inject into the built-in Dashboard, _after_ the default dashboard contents. |
|
|
| **`BeforeLogin`** | An array of Custom Components to inject into the built-in Login, _before_ the default login form. |
|
|
| **`AfterLogin`** | An array of Custom Components to inject into the built-in Login, _after_ the default login form. |
|
|
| **`logout.Button`** | The button displayed in the sidebar that logs the user out. |
|
|
| **`graphics.Icon`** | The simplified logo used in contexts like the the `Nav` component. |
|
|
| **`graphics.Logo`** | The full logo used in contexts like the `Login` view. |
|
|
| **`providers`** | Custom [React Context](https://react.dev/learn/scaling-up-with-reducer-and-context) providers that will wrap the entire [Admin Panel](./overview). [More details](#custom-providers). |
|
|
| **`actions`** | An array of Custom Components to be rendered in the header of the [Admin Panel](./overview), providing additional interactivity and functionality. |
|
|
| **`views`** | Override or create new views within the [Admin Panel](./overview). [More details](./views). |
|
|
|
|
<Banner type="success">
|
|
<strong>Note:</strong> You can also use the `admin.components` property on any Collection Config or Global Config to set [Custom Collection Components](#custom-collection-components) or [Custom Global Components](#custom-global-components).
|
|
</Banner>
|
|
|
|
### Custom Providers
|
|
|
|
You can add additional [React Context](https://react.dev/learn/scaling-up-with-reducer-and-context) to any Payload app through Custom Providers. As you add more and more Custom Components to your [Admin Panel](./overview), this is a great way to share state across all of them.
|
|
|
|
To do this, add `admin.components.providers` to your config:
|
|
|
|
```ts
|
|
import { buildConfig } from 'payload'
|
|
|
|
import { MyProvider } from './MyProvider'
|
|
|
|
export default buildConfig({
|
|
// ...
|
|
admin: {
|
|
components: {
|
|
providers: [MyProvider], // highlight-line
|
|
},
|
|
},
|
|
})
|
|
```
|
|
|
|
Then build your Custom Provider as follows:
|
|
|
|
```tsx
|
|
'use client'
|
|
import React, { createContext, useContext } from 'react'
|
|
|
|
const MyCustomContext = React.createContext(myCustomValue)
|
|
|
|
export const MyProvider: React.FC = ({ children }) => {
|
|
return (
|
|
<MyCustomContext.Provider value={myCustomValue}>
|
|
{children}
|
|
</MyCustomContext.Provider>
|
|
)
|
|
}
|
|
|
|
export const useMyCustomContext = () => useContext(MyCustomContext)
|
|
```
|
|
|
|
<Banner type="warning">
|
|
<strong>Reminder:</strong> Custom Providers are by definition Client Components. This means they must include the `use client` directive at the top of their files and cannot use server-only code.
|
|
</Banner>
|
|
|
|
## Custom Collection Components
|
|
|
|
Collection Components are those that effect [Collection](../configuration/collections)-specific UI within the [Admin Panel](./overview), such as the save button. You can override Collection Components through the `admin.components` property on any [Collection Config](../configuration/collections).
|
|
|
|
Here is an example showing what it might look like to swap out Collection Components for your own. See [Building Custom Components](#building-custom-components) for exact details on how to build them:
|
|
|
|
```ts
|
|
import type { SanitizedCollectionConfig } from 'payload/types'
|
|
import { CustomSaveButton } from './CustomSaveButton'
|
|
|
|
export const MyCollection: SanitizedCollectionConfig = {
|
|
slug: 'my-collection',
|
|
admin: {
|
|
components: {
|
|
edit: {
|
|
SaveButton: CustomSaveButton, // highlight-line
|
|
},
|
|
},
|
|
},
|
|
// ...
|
|
}
|
|
```
|
|
|
|
The following options are available:
|
|
|
|
| Path | Description |
|
|
| -------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
|
|
| **`BeforeList`** | Array of components to inject _before_ the built-in List view |
|
|
| **`BeforeListTable`** | Array of components to inject _before_ the built-in List view's table |
|
|
| **`AfterList`** | Array of components to inject _after_ the built-in List view |
|
|
| **`AfterListTable`** | Array of components to inject _after_ the built-in List view's table |
|
|
| **`edit.SaveButton`** | Replace the default `Save` button with a Custom Component. Drafts must be disabled |
|
|
| **`edit.SaveDraftButton`** | Replace the default `Save Draft` button with a Custom Component. Drafts must be enabled and autosave must be disabled. |
|
|
| **`edit.PublishButton`** | Replace the default `Publish` button with a Custom Component. Drafts must be enabled. |
|
|
| **`edit.PreviewButton`** | Replace the default `Preview` button with a Custom Component. |
|
|
| **`views`** | Override or create new views within the [Admin Panel](./overview). [More details](./views). |
|
|
|
|
## Custom Global Components
|
|
|
|
Global Components are those that effect [Global](../configuration/globals)-specific UI within the [Admin Panel](./overview), such as the save button. You can override Global Components through the `admin.components` property on any [Global Config](../configuration/globals).
|
|
|
|
Here is an example showing what it might look like to swap out Global Components for your own. See [Building Custom Components](#building-custom-components) for exact details on how to build them:
|
|
|
|
```ts
|
|
import type { SanitizedGlobalConfig } from 'payload/types'
|
|
import { CustomSaveButton } from './CustomSaveButton'
|
|
|
|
export const MyGlobal: SanitizedGlobalConfig = {
|
|
slug: 'my-global',
|
|
admin: {
|
|
components: {
|
|
elements: {
|
|
SaveButton: CustomSaveButton, // highlight-line
|
|
},
|
|
},
|
|
},
|
|
// ...
|
|
}
|
|
```
|
|
|
|
The following options are available:
|
|
|
|
| Path | Description |
|
|
| ------------------------------ | ---------------------------------------------------------------------------------------------------------------------- |
|
|
| **`elements.SaveButton`** | Replace the default `Save` button with a Custom Component. Drafts must be disabled. |
|
|
| **`elements.SaveDraftButton`** | Replace the default `Save Draft` button with a Custom Component. Drafts must be enabled and autosave must be disabled. |
|
|
| **`elements.PublishButton`** | Replace the default `Publish` button with a Custom Component. Drafts must be enabled. |
|
|
| **`elements.PreviewButton`** | Replace the default `Preview` button with a Custom Component. |
|
|
| **`views`** | Override or create new views within the [Admin Panel](./overview). [More details](./views). |
|
|
|
|
## Building Custom Components
|
|
|
|
All Custom Components in Payload are [React Server Components](https://react.dev/reference/rsc/server-components) by default, with the exception of [Custom Providers](#custom-providers). This enables the use of the [Local API](../local-api) directly in the front-end.
|
|
|
|
To make building Custom Components as easy as possible, Payload automatically provides common props, such as the [`payload`](../local-api/overview) class and the [`i18n`](../configuration/i18n) object. This means that when building Custom Components within the Admin Panel, you do not have to get these yourself like you would from an external application.
|
|
|
|
Here is an example:
|
|
|
|
```tsx
|
|
import React from 'react'
|
|
|
|
const MyServerComponent = async ({
|
|
payload // highlight-line
|
|
}) => {
|
|
const page = await payload.findByID({
|
|
collection: 'pages',
|
|
id: '123',
|
|
})
|
|
|
|
return (
|
|
<p>{page.title}</p>
|
|
)
|
|
}
|
|
```
|
|
|
|
Each Custom Component receives the following props by default:
|
|
|
|
| Prop | Description |
|
|
| ------------------------- | ----------------------------------------------------------------------------------------------------- |
|
|
| `payload` | The [Payload](../local-api/overview) class. |
|
|
| `i18n` | The [i18n](../i18n) object. |
|
|
|
|
Custom Components also receive various other props that are specific to the context in which the Custom Component is being rendered. For example, [Custom Views](./views) receive the `user` prop. For a full list of available props, consult the documentation related to the specific component you are working with.
|
|
|
|
<Banner type="success">
|
|
See [Root Components](#custom-root-components), [Collection Components](#custom-collection-components), [Global Components](#custom-global-components), or [Field Components](#custom-field-components) for a complete list of all available components.
|
|
</Banner>
|
|
|
|
#### Client Components
|
|
|
|
When [Building Custom Components](#building-custom-components), it's still possible to use client-side code such as `useState` or the `window` object. To do this, simply add the `use client` directive at the top of your file. Payload will automatically detect and remove all default [non-serializable props](https://react.dev/reference/rsc/use-client#serializable-types) before rendering your component.
|
|
|
|
```tsx
|
|
'use client' // highlight-line
|
|
import React, { useState } from 'react'
|
|
|
|
export const MyClientComponent: React.FC = () => {
|
|
const [count, setCount] = useState(0)
|
|
|
|
return (
|
|
<button onClick={() => setCount(count + 1)}>
|
|
Clicked {count} times
|
|
</button>
|
|
)
|
|
}
|
|
```
|
|
|
|
<Banner type="warning">
|
|
<strong>Reminder:</strong>
|
|
Client Components cannot be passed [non-serializable props](https://react.dev/reference/rsc/use-client#serializable-types). If you are rendering your Client Component _from within_ a Server Component, ensure that its props are serializable.
|
|
</Banner>
|
|
|
|
#### Using Hooks
|
|
|
|
To make it easier to [build your Custom Components](#building-custom-components), you can use [Payload's built-in React Hooks](./hooks) in any Client Component. For example, you might want to interact with one of Payload's many React Contexts:
|
|
|
|
```tsx
|
|
'use client'
|
|
import React from 'react'
|
|
import { useDocumentInfo } from '@payloadcms/ui'
|
|
|
|
export const MyClientComponent: React.FC = () => {
|
|
const { slug } = useDocumentInfo()
|
|
|
|
return (
|
|
<p>{`Entity slug: ${slug}`}</p>
|
|
)
|
|
}
|
|
```
|
|
|
|
<Banner type="success">
|
|
See the [Hooks](./hooks) documentation for a full list of available hooks.
|
|
</Banner>
|
|
|
|
#### Getting the Current Language
|
|
|
|
All Custom Components can support multiple languages to be consistent with Payload's [Internationalization](../configuration/i18n). To do this, first add your translation resources to the [I18n Config](../configuration/i18n).
|
|
|
|
From any Server Component, you can translate resources using the `getTranslation` function from `@payloadcms/translations`. All Server Components automatically receive the `i18n` object as a prop by default.
|
|
|
|
```tsx
|
|
import React from 'react'
|
|
import { getTranslation } from '@payloadcms/translations'
|
|
|
|
export default async function MyServerComponent({ i18n }) {
|
|
const translatedTitle = getTranslation(myTranslation, i18n) // highlight-line
|
|
|
|
return (
|
|
<p>{translatedTitle}</p>
|
|
)
|
|
}
|
|
```
|
|
|
|
The best way to do this within a Client Component is to import the `useTranslation` hook from `@payloadcms/ui`:
|
|
|
|
```tsx
|
|
import React from 'react'
|
|
import { useTranslation } from '@payloadcms/ui'
|
|
|
|
export const MyClientComponent: React.FC = () => {
|
|
const { t, i18n } = useTranslation() // highlight-line
|
|
|
|
return (
|
|
<ul>
|
|
<li>{t('namespace1:key', { variable: 'value' })}</li>
|
|
<li>{t('namespace2:key', { variable: 'value' })}</li>
|
|
<li>{i18n.language}</li>
|
|
</ul>
|
|
)
|
|
}
|
|
```
|
|
|
|
<Banner type="success">
|
|
See the [Hooks](./hooks) documentation for a full list of available hooks.
|
|
</Banner>
|
|
|
|
#### Getting the Current Locale
|
|
|
|
All [Custom Views](./views) can support multiple locales to be consistent with Payload's [Localization](../configuration/localization). They automatically receive the `locale` object as a prop by default. This can be used to scope API requests, etc.:
|
|
|
|
```tsx
|
|
import React from 'react'
|
|
|
|
export default async function MyServerComponent({ payload, locale }) {
|
|
const localizedPage = await payload.findByID({
|
|
collection: 'pages',
|
|
id: '123',
|
|
locale,
|
|
})
|
|
|
|
return (
|
|
<p>{localizedPage.title}</p>
|
|
)
|
|
}
|
|
```
|
|
|
|
The best way to do this within a Client Component is to import the `useLocale` hook from `@payloadcms/ui`:
|
|
|
|
```tsx
|
|
import React from 'react'
|
|
import { useLocale } from '@payloadcms/ui'
|
|
|
|
const Greeting: React.FC = () => {
|
|
const locale = useLocale() // highlight-line
|
|
|
|
const trans = {
|
|
en: 'Hello',
|
|
es: 'Hola',
|
|
}
|
|
|
|
return (
|
|
<span>{trans[locale.code]}</span>
|
|
)
|
|
}
|
|
```
|
|
|
|
<Banner type="success">
|
|
See the [Hooks](./hooks) documentation for a full list of available hooks.
|
|
</Banner>
|
|
|
|
#### Styling Custom Components
|
|
|
|
Payload has a robust [CSS Library](./customizing-css) that you can style your Custom Components similarly to Payload's built-in styling. This will ensure that your Custom Component matches the existing design system, and so that it automatically adapts to any theme changes.
|
|
|
|
To apply custom styles, simply import your own `.css` or `.scss` file into your Custom Component:
|
|
|
|
```tsx
|
|
import './index.scss'
|
|
|
|
export const MyComponent: React.FC = () => {
|
|
return (
|
|
<div className="my-component">
|
|
My Custom Component
|
|
</div>
|
|
)
|
|
}
|
|
```
|
|
|
|
Then to colorize your Custom Component's background, for example, you can use the following CSS:
|
|
|
|
```scss
|
|
.my-component {
|
|
background-color: var(--theme-elevation-500);
|
|
}
|
|
```
|
|
|
|
Payload also exports its [SCSS](https://sass-lang.com) library for reuse which includes mixins, etc. To use this, simply import it as follows into your `.scss` file:
|
|
|
|
```scss
|
|
@import '~payload/scss';
|
|
|
|
.my-component {
|
|
@include mid-break {
|
|
background-color: var(--theme-elevation-900);
|
|
}
|
|
}
|
|
|
|
```
|
|
|
|
<Banner type="success">
|
|
<strong>Note:</strong>
|
|
You can also drill into Payload's own component styles, or easily apply global, app-wide CSS. More on that [here](./customizing-css).
|
|
</Banner>
|