6.1 KiB
| title | aliases | tags | sources | created | updated | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Dashboard Widgets |
|
|
|
2026-05-15 | 2026-05-15 |
Dashboard Widgets
Experimental feature — the Modular Dashboard may change in future releases.
The Dashboard is the first screen after login. By default it shows collection/global cards. Custom widgets replace or extend this with any React Server Component content.
Defining Widgets
Add widgets in admin.dashboard.widgets inside buildConfig:
import { buildConfig } from 'payload'
export default buildConfig({
admin: {
dashboard: {
widgets: [
{
slug: 'sales-summary',
Component: './components/SalesSummary.tsx#default',
fields: [
{ name: 'title', type: 'text' },
{ name: 'timeframe', type: 'select', options: ['daily', 'weekly', 'monthly', 'yearly'] },
{ name: 'showTrend', type: 'checkbox' },
],
minWidth: 'small',
maxWidth: 'medium',
},
],
},
},
})
Widget Config Properties
| Property | Type | Description |
|---|---|---|
slug * |
string |
Unique identifier |
Component * |
string |
File path; #name for named exports |
fields |
Field[] |
Optional form fields shown in the widget edit drawer |
minWidth |
WidgetWidth |
Minimum resize width (default: 'x-small') |
maxWidth |
WidgetWidth |
Maximum resize width (default: 'full') |
WidgetWidth values: 'x-small' | 'small' | 'medium' | 'large' | 'x-large' | 'full'
Creating a Widget Component
Widgets are React Server Components receiving WidgetServerProps:
import type { WidgetServerProps } from 'payload'
export default async function UserStatsWidget({ req }: WidgetServerProps) {
const userCount = await req.payload.count({ collection: 'users' })
return (
<div className="card">
<h3>Total Users</h3>
<p style={{ fontSize: '32px', fontWeight: 'bold' }}>{userCount.totalDocs}</p>
</div>
)
}
UI consistency tips:
- Use
className="card"on the root element for the panel background - Use CSS variables:
var(--theme-elevation-0)for bg,var(--theme-text)for text
Typed Widget Data
When fields are defined, type widgetData using generated types:
import type { WidgetServerProps } from 'payload'
import type { SalesSummaryWidget } from '../payload-types'
export default async function SalesSummaryWidgetComponent({
widgetData,
}: WidgetServerProps<SalesSummaryWidget>) {
const title = widgetData?.title ?? 'Sales Summary'
const timeframe = widgetData?.timeframe ?? 'monthly'
return <div className="card"><h3>{title} ({timeframe})</h3></div>
}
Default Layout
Control the initial dashboard layout with defaultLayout — a function receiving req:
dashboard: {
defaultLayout: ({ req }) => {
const isAdmin = req.user?.roles?.includes('admin')
return [
{ widgetSlug: 'collections', width: 'full' },
{ widgetSlug: 'sales-summary', data: { timeframe: 'monthly', title: 'Revenue Overview' }, width: isAdmin ? 'medium' : 'small' },
{ widgetSlug: 'user-stats', width: isAdmin ? 'medium' : 'full' },
]
},
widgets: [ /* ... */ ],
}
WidgetInstance Type
| Property | Type | Description |
|---|---|---|
widgetSlug * |
string |
Slug of the widget to render |
data |
object |
Initial values passed as widgetData to the component |
width |
WidgetWidth |
Initial width (clamped by minWidth/maxWidth) |
defaultLayoutis only applied for first-time visitors or after a layout reset. Returning users see their saved layout.
Built-in Widgets
collections— the default collection/global cards widget- Automatically added if no
defaultLayoutis defined
User Customization Flow
Users can customize their own dashboard via the breadcrumb dropdown → Edit Dashboard:
- Add widgets via "Add +"
- Edit widget field data via the edit button
- Resize via the width dropdown (if multiple widths allowed)
- Reorder via drag-and-drop
- Delete widgets
- Save or cancel changes
- Reset to
defaultLayoutvia "Reset Layout"
Layouts are persisted to user preferences in the database.
Plugin Widgets
Each plugin can register its own widgets. Common plugin use cases:
- Analytics dashboards
- Error reporting (Sentry)
- Document count filters
- Recent jobs executed
Key Takeaways
- Experimental — API may change;
admin.dashboard.widgetsarray inbuildConfig - Widget components are RSC — fetch data server-side via
req.payload.* fieldsarray adds a config drawer for per-instance data (typed via generatedpayload-types)defaultLayoutfunction receivesreq— use it to customize layout per user role- Users can fully customize and save their own layout;
defaultLayout= first-visit default only - Built-in
collectionswidget is auto-added if nodefaultLayoutis set - Use
className="card"+ CSS theme variables for visual consistency with Payload UI - Plugins can contribute their own widgets
Related
- wiki/payloadcms/custom-components — root slots, edit/list view slots, providers
- wiki/payloadcms/react-hooks —
usePreferences,useAuth,useDocumentInfo - wiki/payloadcms/admin-preferences — per-user preference storage (where layouts are saved)
- wiki/payloadcms/plugins-api — how plugins can register their own widgets
- wiki/payloadcms/custom-views — full custom Admin Panel pages (vs widgets)