297 lines
8 KiB
Markdown
297 lines
8 KiB
Markdown
---
|
|
title: "Payload CMS React Hooks"
|
|
aliases: [payload-react-hooks, payloadcms-hooks, useField, useForm, useDocumentInfo]
|
|
tags: [payloadcms, react, hooks, custom-components, admin-panel]
|
|
sources: [raw/admin__react-hooks.md]
|
|
created: 2026-05-15
|
|
updated: 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|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.
|
|
|
|
```tsx
|
|
'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`:
|
|
|
|
```tsx
|
|
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`).
|
|
|
|
```tsx
|
|
'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.
|
|
|
|
```tsx
|
|
'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`
|
|
|
|
```tsx
|
|
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`
|
|
|
|
```tsx
|
|
const { id } = useDocumentInfo()
|
|
// id is undefined on create form
|
|
```
|
|
|
|
---
|
|
|
|
### `useDocumentTitle`
|
|
|
|
Returns document title without triggering re-renders on other document state changes.
|
|
|
|
```tsx
|
|
const { title, setDocumentTitle } = useDocumentTitle()
|
|
```
|
|
|
|
---
|
|
|
|
### `useDocumentEvents`
|
|
|
|
Subscribe to cross-document events (e.g., nested doc updated in a drawer).
|
|
|
|
```tsx
|
|
const { mostRecentUpdate, reportUpdate } = useDocumentEvents()
|
|
// mostRecentUpdate: { entitySlug, id?, updatedAt }
|
|
```
|
|
|
|
---
|
|
|
|
## List View Hooks
|
|
|
|
### `useListQuery`
|
|
|
|
Subscribe to list view data and query state.
|
|
|
|
```tsx
|
|
const { data, query } = useListQuery()
|
|
```
|
|
|
|
Key properties: `data`, `query`, `defaultLimit`, `defaultSort`, `modified`, `handlePageChange`, `handlePerPageChange`, `handleSearchChange`, `handleSortChange`, `handleWhereChange`
|
|
|
|
---
|
|
|
|
### `useSelection`
|
|
|
|
Access/control row selection in list view.
|
|
|
|
```tsx
|
|
const { count, toggleAll, totalDocs, selected, setSelection, getQueryParams, selectAll } = useSelection()
|
|
// selectAll enum: 'allAvailable' | 'allInPage' | 'none' | 'some'
|
|
```
|
|
|
|
---
|
|
|
|
### `useTableColumns`
|
|
|
|
Manage list view column visibility and order.
|
|
|
|
```tsx
|
|
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.
|
|
|
|
```tsx
|
|
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.
|
|
|
|
```tsx
|
|
const { startRouteTransition } = useRouteTransition()
|
|
startRouteTransition(() => router.push('/somewhere'))
|
|
```
|
|
|
|
---
|
|
|
|
## Auth / Config / Preferences / Theme
|
|
|
|
### `useAuth`
|
|
|
|
```tsx
|
|
const { user, token, logOut, refreshCookie, setToken, refreshPermissions, permissions } = useAuth<User>()
|
|
```
|
|
|
|
### `useConfig`
|
|
|
|
```tsx
|
|
const { config, getEntityConfig } = useConfig()
|
|
const mediaConfig = getEntityConfig({ collectionSlug: 'media' })
|
|
```
|
|
|
|
### `useLocale`
|
|
|
|
```tsx
|
|
const locale = useLocale() // { code, label, rtl }
|
|
```
|
|
|
|
### `useTheme`
|
|
|
|
```tsx
|
|
const { theme, setTheme, autoMode } = useTheme()
|
|
// theme: 'light' | 'dark' | 'auto'
|
|
```
|
|
|
|
### `usePreferences`
|
|
|
|
Get/set persistent user preferences. See [[wiki/payloadcms/admin-preferences|Admin Preferences]] for full docs.
|
|
|
|
---
|
|
|
|
## `usePayloadAPI`
|
|
|
|
Reactive REST API requests to Payload.
|
|
|
|
```tsx
|
|
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` > `useAllFormFields` for performance — only subscribes to specific fields
|
|
- **Lexical rich text**: `setValue` updates data but not the UI — use `dispatchFields` with both `value` + `initialValue`
|
|
- `useForm` fields property is deprecated/stale — use it only for action callbacks, not reactive state
|
|
- `useDocumentForm` vs `useForm`: use the former when inside nested forms (Lexical blocks)
|
|
- `dispatchFields` `UPDATE` action is the low-level escape hatch for any field state mutation
|
|
- `useDocumentTitle` is split from `useDocumentInfo` to prevent unnecessary re-renders
|
|
|
|
---
|
|
|
|
## Related
|
|
|
|
- [[wiki/payloadcms/custom-components|Custom Components]] — where hooks are used
|
|
- [[wiki/payloadcms/admin-preferences|Admin Preferences]] — `usePreferences` deep dive
|
|
- [[wiki/payloadcms/admin-panel-overview|Admin Panel Overview]] — full admin config
|
|
|
|
---
|
|
|
|
## Sources
|
|
|
|
- `raw/admin__react-hooks.md`
|
|
- Official docs: https://payloadcms.com/docs/admin/react-hooks
|