feat: configurable toast notifications (#13609)

Follow up to #12119.

You can now configure the toast notifications used in the admin panel
through the Payload config:

```ts
import { buildConfig } from 'payload'

export default buildConfig({
  // ...
  admin: {
    // ...
    toast: {
      duration: 8000,
      limit: 1,
      // ...
    }
  }
})
```

_Note: the toast config is temporarily labeled as experimental to allow
for changes to the API, if necessary._

---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
  - https://app.asana.com/0/0/1211139422639711
This commit is contained in:
Jacob Fletcher
2025-08-27 15:10:01 -04:00
committed by GitHub
parent 5ded64eaaf
commit 0a18306599
5 changed files with 54 additions and 4 deletions

View File

@@ -107,6 +107,7 @@ The following options are available:
| `suppressHydrationWarning` | If set to `true`, suppresses React hydration mismatch warnings during the hydration of the root `<html>` tag. Defaults to `false`. | | `suppressHydrationWarning` | If set to `true`, suppresses React hydration mismatch warnings during the hydration of the root `<html>` tag. Defaults to `false`. |
| `theme` | Restrict the Admin Panel theme to use only one of your choice. Default is `all`. | | `theme` | Restrict the Admin Panel theme to use only one of your choice. Default is `all`. |
| `timezones` | Configure the timezone settings for the admin panel. [More details](#timezones) | | `timezones` | Configure the timezone settings for the admin panel. [More details](#timezones) |
| `toast` | Customize the handling of toast messages within the Admin Panel. [More details](#toasts) |
| `user` | The `slug` of the Collection that you want to allow to login to the Admin Panel. [More details](#the-admin-user-collection). | | `user` | The `slug` of the Collection that you want to allow to login to the Admin Panel. [More details](#the-admin-user-collection). |
<Banner type="success"> <Banner type="success">
@@ -298,3 +299,20 @@ We validate the supported timezones array by checking the value against the list
`timezone: true`. See [Date Fields](../fields/overview#date) for more `timezone: true`. See [Date Fields](../fields/overview#date) for more
information. information.
</Banner> </Banner>
## Toast
The `admin.toast` configuration allows you to customize the handling of toast messages within the Admin Panel, such as increasing the duration they are displayed and limiting the number of visible toasts at once.
<Banner type="info">
**Note:** The Admin Panel currently uses the
[Sonner](https://sonner.emilkowal.ski) library for toast notifications.
</Banner>
The following options are available for the `admin.toast` configuration:
| Option | Description | Default |
| ---------- | ---------------------------------------------------------------------------------------------------------------- | ------- |
| `duration` | The length of time (in milliseconds) that a toast message is displayed. | `4000` |
| `expand` | If `true`, will expand the message stack so that all messages are shown simultaneously without user interaction. | `false` |
| `limit` | The maximum number of toasts that can be visible on the screen at once. | `5` |

View File

@@ -116,6 +116,7 @@ export const createClientConfig = ({
routes: config.admin.routes, routes: config.admin.routes,
theme: config.admin.theme, theme: config.admin.theme,
timezones: config.admin.timezones, timezones: config.admin.timezones,
toast: config.admin.toast,
user: config.admin.user, user: config.admin.user,
} }

View File

@@ -752,7 +752,6 @@ export type Config = {
username?: string username?: string
} }
| false | false
/** Set account profile picture. Options: gravatar, default or a custom React component. */ /** Set account profile picture. Options: gravatar, default or a custom React component. */
avatar?: avatar?:
| 'default' | 'default'
@@ -760,6 +759,7 @@ export type Config = {
| { | {
Component: PayloadComponent Component: PayloadComponent
} }
/** /**
* Add extra and/or replace built-in components with custom components * Add extra and/or replace built-in components with custom components
* *
@@ -939,6 +939,29 @@ export type Config = {
* Configure timezone related settings for the admin panel. * Configure timezone related settings for the admin panel.
*/ */
timezones?: TimezonesConfig timezones?: TimezonesConfig
/**
* @experimental
* Configure toast message behavior and appearance in the admin panel.
* Currently using [Sonner](https://sonner.emilkowal.ski) for toast notifications.
*/
toast?: {
/**
* Time in milliseconds until the toast automatically closes.
* @default 4000
*/
duration?: number
/**
* If `true`, will expand the message stack so that all messages are shown simultaneously without user interaction.
* Otherwise only the latest notification can be read until the user hovers the stack.
* @default false
*/
expand?: boolean
/**
* The maximum number of toasts that can be visible on the screen at once.
* @default 5
*/
limit?: number
}
/** The slug of a Collection that you want to be used to log in to the Admin dashboard. */ /** The slug of a Collection that you want to be used to log in to the Admin dashboard. */
user?: string user?: string
} }

View File

@@ -139,7 +139,7 @@ export const RootProvider: React.FC<Props> = ({
</RouteCache> </RouteCache>
</RouteTransitionProvider> </RouteTransitionProvider>
</ServerFunctionsProvider> </ServerFunctionsProvider>
<ToastContainer /> <ToastContainer config={config} />
</ClickOutsideProvider> </ClickOutsideProvider>
) )
} }

View File

@@ -1,4 +1,6 @@
'use client' 'use client'
import type { ClientConfig } from 'payload'
import React from 'react' import React from 'react'
import { Toaster } from 'sonner' import { Toaster } from 'sonner'
@@ -7,13 +9,19 @@ import { Info } from './icons/Info.js'
import { Success } from './icons/Success.js' import { Success } from './icons/Success.js'
import { Warning } from './icons/Warning.js' import { Warning } from './icons/Warning.js'
export const ToastContainer: React.FC = () => { export const ToastContainer: React.FC<{
config: ClientConfig
}> = ({ config }) => {
const { admin: { toast: { duration, expand, limit } = {} } = {} } = config
return ( return (
<Toaster <Toaster
className="payload-toast-container" className="payload-toast-container"
closeButton closeButton
// @ts-expect-error // @ts-expect-error
dir="undefined" dir="undefined"
duration={duration ?? 4000}
expand={expand ?? false}
gap={8} gap={8}
icons={{ icons={{
error: <Error />, error: <Error />,
@@ -36,7 +44,7 @@ export const ToastContainer: React.FC = () => {
}, },
unstyled: true, unstyled: true,
}} }}
visibleToasts={5} visibleToasts={limit ?? 5}
/> />
) )
} }