Кастомные компоненты admin panel Payload CMS
Payload позволяет переопределять и расширять admin panel с помощью React компонентов. Это не патчинг — Payload предоставляет официальные слоты для подстановки кастомных компонентов в заголовок, навигацию, dashboard и отдельные поля.
Dashboard компоненты
// payload.config.ts
export default buildConfig({
admin: {
components: {
// Главная страница дашборда
views: {
Dashboard: '/components/admin/Dashboard#CustomDashboard',
},
// Дополнительные элементы в навигации
afterNavLinks: ['/components/admin/NavExtras#NavExtras'],
// Элементы в заголовке
afterDashboard: ['/components/admin/DashboardStats#DashboardStats'],
// Логотип
graphics: {
Logo: '/components/admin/Logo#Logo',
Icon: '/components/admin/Icon#Icon',
},
},
},
})
// components/admin/DashboardStats.tsx
'use client'
import { useEffect, useState } from 'react'
interface Stats {
totalOrders: number
totalRevenue: number
newUsers: number
}
export const DashboardStats = () => {
const [stats, setStats] = useState<Stats | null>(null)
useEffect(() => {
fetch('/api/admin/stats')
.then(r => r.json())
.then(setStats)
}, [])
if (!stats) return <div>Загрузка...</div>
return (
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 16, padding: '16px 0' }}>
<StatCard label="Заказов сегодня" value={stats.totalOrders} />
<StatCard label="Выручка" value={`${stats.totalRevenue.toLocaleString()} ₽`} />
<StatCard label="Новых пользователей" value={stats.newUsers} />
</div>
)
}
const StatCard = ({ label, value }: { label: string; value: any }) => (
<div style={{ background: '#fff', border: '1px solid #e0e0e0', borderRadius: 8, padding: 16 }}>
<div style={{ fontSize: 12, color: '#666' }}>{label}</div>
<div style={{ fontSize: 24, fontWeight: 700 }}>{value}</div>
</div>
)
Кастомный просмотр коллекции (custom view)
// collections/Orders.ts
const Orders: CollectionConfig = {
slug: 'orders',
admin: {
components: {
views: {
// Добавить вкладку "Аналитика" к коллекции
Edit: {
Analytics: {
Component: '/components/admin/OrderAnalytics#OrderAnalytics',
path: '/analytics',
Tab: {
label: 'Аналитика',
href: '/analytics',
},
},
},
},
},
},
}
// components/admin/OrderAnalytics.tsx
'use client'
import { useDocumentInfo } from 'payload/components/utilities'
export const OrderAnalytics = () => {
const { id } = useDocumentInfo()
// Отображение аналитики для конкретного заказа
return (
<div>
<h2>Аналитика заказа {id}</h2>
{/* Кастомные графики, таймлайн */}
</div>
)
}
Кастомный компонент поля
// components/admin/fields/SlugField.tsx
'use client'
import { useField, useFormFields } from 'payload/components/forms'
import { useEffect } from 'react'
export const SlugField = ({ path }: { path: string }) => {
const { value, setValue } = useField<string>({ path })
const title = useFormFields(([fields]) => fields.title?.value as string)
const generateSlug = (str: string) =>
str.toLowerCase()
.replace(/[а-яё]/g, char => translitMap[char] || char)
.replace(/\s+/g, '-')
.replace(/[^\w-]/g, '')
return (
<div>
<label>URL Slug</label>
<div style={{ display: 'flex', gap: 8 }}>
<input
type="text"
value={value || ''}
onChange={e => setValue(e.target.value)}
/>
<button
type="button"
onClick={() => title && setValue(generateSlug(title))}
>
Из заголовка
</button>
</div>
</div>
)
}
Кнопки действий в форме редактирования
// collections/Products.ts
{
admin: {
components: {
edit: {
// Дополнительные кнопки в header формы
SaveButton: '/components/admin/ProductActions#ProductActions',
},
},
},
}
// components/admin/ProductActions.tsx
'use client'
import { useDocumentInfo, useForm } from 'payload/components/utilities'
export const ProductActions = () => {
const { id } = useDocumentInfo()
const { submit } = useForm()
const handleDuplicate = async () => {
await fetch(`/api/products/${id}/duplicate`, { method: 'POST' })
}
return (
<div style={{ display: 'flex', gap: 8 }}>
<button onClick={handleDuplicate} type="button">
Дублировать
</button>
<button onClick={submit} type="button">
Сохранить
</button>
</div>
)
}
Кастомный логотип
// components/admin/Logo.tsx
export const Logo = () => (
<img src="/logo.svg" alt="Company Name" height={40} />
)
// payload.config.ts
admin: {
components: {
graphics: {
Logo: '/components/admin/Logo#Logo',
},
},
css: '/styles/admin-custom.css', // кастомные CSS стили для admin
}
Сроки
Разработка кастомных admin-компонентов (dashboard со статистикой, кастомные поля, дополнительные вкладки) — 2–4 дня в зависимости от сложности UI.







