obsidian/wiki/payloadcms/react-hooks.md
2026-05-15 15:13:56 +01:00

8 KiB

title aliases tags sources created updated
Payload CMS React Hooks
payload-react-hooks
payloadcms-hooks
useField
useForm
useDocumentInfo
payloadcms
react
hooks
custom-components
admin-panel
raw/admin__react-hooks.md
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 > 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


Sources