8 KiB
| title | aliases | tags | sources | created | updated | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Payload CMS React Hooks |
|
|
|
2026-05-15 | 2026-05-15 |
Payload CMS React Hooks
All hooks come from @payloadcms/ui. Only available in client components — add 'use client' directive. Default wiki/payloadcms/custom-components are React Server Components; hooks require opting into client mode.
Form / Field Hooks
useField
Core hook for custom field components — reads/writes a single field's value in the parent form.
'use client'
import { useField } from '@payloadcms/ui'
const { value, setValue } = useField({ path: 'myField' })
Arguments:
| Prop | Description |
|---|---|
path |
Path to the field in form data (falls back to name) |
validate |
Client-side validation before server submit |
disableFormData |
Exclude field from form submission |
hasRows |
Mark as row-based (array/blocks) |
Returns: { value, setValue, initialValue, errorMessage, errorPaths, readOnly, formProcessing, formSubmitted, showError, valid, rows, permissions, ... }
Lexical Rich Text Gotcha
setValue updates form data but the editor UI will not re-render. To visually update a Lexical field, use dispatchFields with UPDATE action setting both value AND initialValue:
dispatchFields({
type: 'UPDATE',
path: 'myRichTextField',
value: newValue,
initialValue: newValue, // required to trigger Lexical re-mount
})
useFormFields
Retrieve specific fields from form state with a selector — performant, only re-renders when selected fields change (uses use-context-selector).
'use client'
import { useFormFields } from '@payloadcms/ui'
const amount = useFormFields(([fields]) => fields.amount)
const fee = useFormFields(([fields]) => fields.feePercentage)
useAllFormFields
Retrieve all fields + dispatchFields. Re-renders on any field change — use sparingly.
'use client'
import { useAllFormFields } from '@payloadcms/ui'
import { reduceFieldsToValues, getSiblingData } from 'payload/shared'
const [fields, dispatchFields] = useAllFormFields()
const formData = reduceFieldsToValues(fields, true)
const sibling = getSiblingData(fields, 'someField')
dispatchFields actions:
| Action | Use case |
|---|---|
ADD_ROW |
Add row to array/blocks |
DUPLICATE_ROW |
Duplicate row |
MODIFY_CONDITION |
Toggle conditional logic |
MOVE_ROW |
Reorder rows |
REMOVE |
Remove field from state |
REMOVE_ROW |
Remove row from array/blocks |
REPLACE_STATE |
Full form state replacement |
UPDATE |
Update any field property |
useForm
Interact with the form itself (actions triggered by user events). Do not rely on fields for up-to-date values — it's deprecated/stale. Use only for action-based callbacks.
Key methods: submit, validateForm, createFormData, getData, getField, getFields, getSiblingData, getDataByPath, reset, addFieldRow, removeFieldRow, replaceFieldRow, setModified, setProcessing, setSubmitted
const { addFieldRow } = useForm()
addFieldRow({
path: 'arrayField',
schemaPath: 'arrayField',
rowIndex: 0,
subFieldState: { textField: { initialValue: 'text', valid: true, value: 'text' } },
// blockType: 'slug' // required for block arrays
})
useDocumentForm
Same as useForm but always targets the top-level document form — useful inside Lexical blocks or other child forms that create their own Form context.
Document / Collection Hooks
useDocumentInfo
Comprehensive info about the document being edited.
Key properties: id, collectionSlug, globalSlug, docPermissions, isEditing, isLocked, documentIsLocked, hasPublishedDoc, hasPublishPermission, hasSavePermission, initialData, data, versionCount, currentEditor, apiURL, uploadStatus
Key methods: getDocPermissions, getDocPreferences, setDocFieldPreferences, unlockDocument, updateDocumentEditor, updateSavedDocumentData
const { id } = useDocumentInfo()
// id is undefined on create form
useDocumentTitle
Returns document title without triggering re-renders on other document state changes.
const { title, setDocumentTitle } = useDocumentTitle()
useDocumentEvents
Subscribe to cross-document events (e.g., nested doc updated in a drawer).
const { mostRecentUpdate, reportUpdate } = useDocumentEvents()
// mostRecentUpdate: { entitySlug, id?, updatedAt }
List View Hooks
useListQuery
Subscribe to list view data and query state.
const { data, query } = useListQuery()
Key properties: data, query, defaultLimit, defaultSort, modified, handlePageChange, handlePerPageChange, handleSearchChange, handleSortChange, handleWhereChange
useSelection
Access/control row selection in list view.
const { count, toggleAll, totalDocs, selected, setSelection, getQueryParams, selectAll } = useSelection()
// selectAll enum: 'allAvailable' | 'allInPage' | 'none' | 'some'
useTableColumns
Manage list view column visibility and order.
const { columns, setActiveColumns, toggleColumn, moveColumn, resetColumnsState } = useTableColumns()
setActiveColumns(['id', 'createdAt']) // activates specific cols, preserves order
UI / Navigation Hooks
useCollapsible
Control nearest collapsible: { isCollapsed, isVisible, toggle, isWithinCollapsible }
useStepNav
Set breadcrumb nav in app header.
const { setStepNav } = useStepNav()
// StepNavItem: { label: string, url?: string }
useEditDepth
How many modal/drawer nesting levels deep the component is.
useRouteTransition
Wrap router.push to show visual transition feedback.
const { startRouteTransition } = useRouteTransition()
startRouteTransition(() => router.push('/somewhere'))
Auth / Config / Preferences / Theme
useAuth
const { user, token, logOut, refreshCookie, setToken, refreshPermissions, permissions } = useAuth<User>()
useConfig
const { config, getEntityConfig } = useConfig()
const mediaConfig = getEntityConfig({ collectionSlug: 'media' })
useLocale
const locale = useLocale() // { code, label, rtl }
useTheme
const { theme, setTheme, autoMode } = useTheme()
// theme: 'light' | 'dark' | 'auto'
usePreferences
Get/set persistent user preferences. See wiki/payloadcms/admin-preferences for full docs.
usePayloadAPI
Reactive REST API requests to Payload.
const [{ data, isError, isLoading }, { setParams }] = usePayloadAPI('/api/posts/123', {
initialParams: { depth: 1 },
})
setParams({ cacheBust: Date.now() }) // trigger refetch
Key Takeaways
- All hooks require
'use client'— they cannot run in Server Components useFormFields>useAllFormFieldsfor performance — only subscribes to specific fields- Lexical rich text:
setValueupdates data but not the UI — usedispatchFieldswith bothvalue+initialValue useFormfields property is deprecated/stale — use it only for action callbacks, not reactive stateuseDocumentFormvsuseForm: use the former when inside nested forms (Lexical blocks)dispatchFieldsUPDATEaction is the low-level escape hatch for any field state mutationuseDocumentTitleis split fromuseDocumentInfoto prevent unnecessary re-renders
Related
- wiki/payloadcms/custom-components — where hooks are used
- wiki/payloadcms/admin-preferences —
usePreferencesdeep dive - wiki/payloadcms/admin-panel-overview — full admin config
Sources
raw/admin__react-hooks.md- Official docs: https://payloadcms.com/docs/admin/react-hooks