--- title: React Hooks label: React Hooks order: 70 desc: Make use of all of the powerful React hooks that Payload provides. keywords: admin, components, custom, documentation, Content Management System, cms, headless, javascript, node, react, nextjs --- Payload provides a variety of powerful [React Hooks](https://react.dev/reference/react-dom/hooks) that can be used within your own [Custom Components](./components), such as [Custom Fields](./fields). With them, you can interface with Payload itself to build just about any type of complex customization you can think of. **Reminder:** All Custom Components are [React Server Components](https://react.dev/reference/rsc/server-components) by default. Hooks, on the other hand, are only available in client-side environments. To use hooks, [ensure your component is a client component](./components#client-components). ## useField The `useField` hook is used internally within all field components. It manages sending and receiving a field's state from its parent form. When you build a [Custom Field Component](./fields), you will be responsible for sending and receiving the field's `value` to and from the form yourself. To do so, import the `useField` hook as follows: ```tsx 'use client' import type { TextFieldClientComponent } from 'payload' import { useField } from '@payloadcms/ui' export const CustomTextField: TextFieldClientComponent = ({ path }) => { const { value, setValue } = useField({ path }) // highlight-line return (

{path}

{ setValue(e.target.value) }} value={value} />
) } ``` The `useField` hook accepts the following arguments: | Property | Description | | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `path` | If you do not provide a `path`, `name` will be used instead. This is the path to the field in the form data. | | `validate` | A validation function executed client-side _before_ submitting the form to the server. Different than [Field-level Validation](../fields/overview#validation) which runs strictly on the server. | | `disableFormData` | If `true`, the field will not be included in the form data when the form is submitted. | | `hasRows` | If `true`, the field will be treated as a field with rows. This is useful for fields like `array` and `blocks`. | The `useField` hook returns the following object: ```ts type FieldType = { errorMessage?: string errorPaths?: string[] filterOptions?: FilterOptionsResult formInitializing: boolean formProcessing: boolean formSubmitted: boolean initialValue?: T path: string permissions: FieldPermissions readOnly?: boolean rows?: Row[] schemaPath: string setValue: (val: unknown, disableModifyingForm?: boolean) => void showError: boolean valid?: boolean value: T } ``` ## useFormFields There are times when a custom field component needs to have access to data from other fields, and you have a few options to do so. The `useFormFields` hook is a powerful and highly performant way to retrieve a form's field state, as well as to retrieve the `dispatchFields` method, which can be helpful for setting other fields' form states from anywhere within a form. **This hook is great for retrieving only certain fields from form state** because it ensures that it will only cause a rerender when the items that you ask for change. Thanks to the awesome package [`use-context-selector`](https://github.com/dai-shi/use-context-selector), you can retrieve a specific field's state easily. This is ideal because you can ensure you have an up-to-date field state, and your component will only re-render when _that field's state_ changes. You can pass a Redux-like selector into the hook, which will ensure that you retrieve only the field that you want. The selector takes an argument with type of `[fields: Fields, dispatch: React.Dispatch]]`. ```tsx 'use client' import { useFormFields } from '@payloadcms/ui' const MyComponent: React.FC = () => { // Get only the `amount` field state, and only cause a rerender when that field changes const amount = useFormFields(([fields, dispatch]) => fields.amount) // Do the same thing as above, but to the `feePercentage` field const feePercentage = useFormFields(([fields, dispatch]) => fields.feePercentage) if (typeof amount?.value !== 'undefined' && typeof feePercentage?.value !== 'undefined') { return The fee is ${(amount.value * feePercentage.value) / 100} } } ``` ## useAllFormFields **To retrieve more than one field**, you can use the `useAllFormFields` hook. Your component will re-render when _any_ field changes, so use this hook only if you absolutely need to. Unlike the `useFormFields` hook, this hook does not accept a "selector", and it always returns an array with type of `[fields: Fields, dispatch: React.Dispatch]]`. You can do lots of powerful stuff by retrieving the full form state, like using built-in helper functions to reduce field state to values only, or to retrieve sibling data by path. ```tsx 'use client' import { useAllFormFields } from '@payloadcms/ui' import { reduceFieldsToValues, getSiblingData } from 'payload/shared' const ExampleComponent: React.FC = () => { // the `fields` const will be equal to all fields' state, // and the `dispatchFields` method is usable to send field state up to the form const [fields, dispatchFields] = useAllFormFields(); // Pass in fields, and indicate if you'd like to "unflatten" field data. // The result below will reflect the data stored in the form at the given time const formData = reduceFieldsToValues(fields, true); // Pass in field state and a path, // and you will be sent all sibling data of the path that you've specified const siblingData = getSiblingData(fields, 'someFieldName'); return ( // return some JSX here if necessary ) }; ``` #### Updating other fields' values If you are building a Custom Component, then you should use `setValue` which is returned from the `useField` hook to programmatically set your field's value. But if you're looking to update _another_ field's value, you can use `dispatchFields` returned from `useFormFields`. You can send the following actions to the `dispatchFields` function. | Action | Description | | ---------------------- | -------------------------------------------------------------------------- | | **`ADD_ROW`** | Adds a row of data (useful in array / block field data) | | **`DUPLICATE_ROW`** | Duplicates a row of data (useful in array / block field data) | | **`MODIFY_CONDITION`** | Updates a field's conditional logic result (true / false) | | **`MOVE_ROW`** | Moves a row of data (useful in array / block field data) | | **`REMOVE`** | Removes a field from form state | | **`REMOVE_ROW`** | Removes a row of data from form state (useful in array / block field data) | | **`REPLACE_STATE`** | Completely replaces form state | | **`UPDATE`** | Update any property of a specific field's state | To see types for each action supported within the `dispatchFields` hook, check out the Form types [here](https://github.com/payloadcms/payload/blob/main/packages/ui/src/forms/Form/types.ts). ## useForm The `useForm` hook can be used to interact with the form itself, and sends back many methods that can be used to reactively fetch form state without causing rerenders within your components each time a field is changed. This is useful if you have action-based callbacks that your components fire, and need to interact with form state _based on a user action_. **Warning:** This hook is optimized to avoid causing rerenders when fields change, and as such, its `fields` property will be out of date. You should only leverage this hook if you need to perform actions against the form in response to your users' actions. Do not rely on its returned "fields" as being up-to-date. They will be removed from this hook's response in an upcoming version. The `useForm` hook returns an object with the following properties: \`\`\`tsx import { useForm } from "payload/components/forms"; export const CustomArrayManager = () => { const { addFieldRow } = useForm() return ( ) } \`\`\` An example config to go along with the Custom Component \`\`\`tsx const ExampleCollection = { slug: "example-collection", fields: [ { name: "arrayField", type: "array", fields: [ { name: "textField", type: "text", }, ], }, { type: "ui", name: "customArrayManager", admin: { components: { Field: '/path/to/CustomArrayManagerField', }, }, }, ], } \`\`\` ` } ], [ { value: "**`removeFieldRow`**", }, { value: "Method to remove a row from an array or block field", }, { drawerTitle: 'removeFieldRow', drawerDescription: 'A useful method to programmatically remove a row from an array or block field.', drawerSlug: 'removeFieldRow', drawerContent: ` \`\`\`tsx import { useForm } from "payload/components/forms"; export const CustomArrayManager = () => { const { removeFieldRow } = useForm() return ( ) } \`\`\` An example config to go along with the Custom Component \`\`\`tsx const ExampleCollection = { slug: "example-collection", fields: [ { name: "arrayField", type: "array", fields: [ { name: "textField", type: "text", }, ], }, { type: "ui", name: "customArrayManager", admin: { components: { Field: '/path/to/CustomArrayManagerField', }, }, }, ], } \`\`\` ` } ], [ { value: "**`replaceFieldRow`**", }, { value: "Method to replace a row from an array or block field", }, { drawerTitle: 'replaceFieldRow', drawerDescription: 'A useful method to programmatically replace a row from an array or block field.', drawerSlug: 'replaceFieldRow', drawerContent: ` \`\`\`tsx import { useForm } from "payload/components/forms"; export const CustomArrayManager = () => { const { replaceFieldRow } = useForm() return ( ) } \`\`\` An example config to go along with the Custom Component \`\`\`tsx const ExampleCollection = { slug: "example-collection", fields: [ { name: "arrayField", type: "array", fields: [ { name: "textField", type: "text", }, ], }, { type: "ui", name: "customArrayManager", admin: { components: { Field: '/path/to/CustomArrayManagerField', }, }, }, ], } \`\`\` ` } ], ]} /> ## useCollapsible The `useCollapsible` hook allows you to control parent collapsibles: | Property | Description | | ------------------------- | ------------------------------------------------------------------------------------------------------------- | | **`isCollapsed`** | State of the collapsible. `true` if open, `false` if collapsed. | | **`isVisible`** | If nested, determine if the nearest collapsible is visible. `true` if no parent is closed, `false` otherwise. | | **`toggle`** | Toggles the state of the nearest collapsible. | | **`isWithinCollapsible`** | Determine when you are within another collapsible. | **Example:** ```tsx 'use client' import React from 'react' import { useCollapsible } from '@payloadcms/ui' const CustomComponent: React.FC = () => { const { isCollapsed, toggle } = useCollapsible() return (

I am {isCollapsed ? 'closed' : 'open'}

) } ``` ## useDocumentInfo The `useDocumentInfo` hook provides information about the current document being edited, including the following: | Property | Description | | ------------------------- | ------------------------------------------------------------------------------------------------------------------ | | **`currentEditor`** | The user currently editing the document. | | **`docConfig`** | Either the Collection or Global config of the document, depending on what is being edited. | | **`documentIsLocked`** | Whether the document is currently locked by another user. | | **`id`** | If the doc is a collection, its ID will be returned | | **`getDocPermissions`** | Method to retrieve document-level user preferences. | | **`getDocPreferences`** | Method to retrieve document-level user preferences. | | **`hasPublishedDoc`** | Whether the document has a published version. | | **`incrementVersionCount`** | Method to increment the version count of the document. | | **`preferencesKey`** | The `preferences` key to use when interacting with document-level user preferences. | | **`versions`** | Versions of the current doc. | | **`unpublishedVersions`** | Unpublished versions of the current doc. | | **`publishedDoc`** | The currently published version of the doc being edited. | | **`getVersions`** | Method to retrieve document versions. | | **`docPermissions`** | The current documents permissions. Collection document permissions fallback when no id is present (i.e. on create). | | **`versionCount`** | The current version count of the document. | **Example:** ```tsx 'use client' import { useDocumentInfo } from '@payloadcms/ui' const LinkFromCategoryToPosts: React.FC = () => { // highlight-start const { id } = useDocumentInfo() // highlight-end // id will be undefined on the create form if (!id) { return null } return ( View posts ) } ``` ## useListQuery The `useListQuery` hook is used to subscribe to the data, current query, and other properties used within the List View. You can use this hook within any Custom Component rendered within the List View. ```tsx 'use client' import { useListQuery } from '@payloadcms/ui' const MyComponent: React.FC = () => { // highlight-start const { data, query } = useListQuery() // highlight-end // ... } ``` The `useListQuery` hook returns an object with the following properties: | Property | Description | | ----------------- | --------------------------------------------------------------------------------------------- | | **`data`** | The data that is being displayed in the List View. | | **`defaultLimit`**| The default limit of items to display in the List View. | | **`defaultSort`** | The default sort order of items in the List View. | | **`handlePageChange`** | A method to handle page changes in the List View. | | **`handlePerPageChange`** | A method to handle per page changes in the List View. | | **`handleSearchChange`** | A method to handle search changes in the List View. | | **`handleSortChange`** | A method to handle sort changes in the List View. | | **`handleWhereChange`** | A method to handle where changes in the List View. | | **`query`** | The current query that is being used to fetch the data in the List View. | ## useLocale In any Custom Component you can get the selected locale object with the `useLocale` hook. `useLocale` gives you the full locale object, consisting of a `label`, `rtl`(right-to-left) property, and then `code`. Here is a simple example: ```tsx 'use client' import { useLocale } from '@payloadcms/ui' const Greeting: React.FC = () => { // highlight-start const locale = useLocale() // highlight-end const trans = { en: 'Hello', es: 'Hola', } return {trans[locale.code]} } ``` ## useAuth Useful to retrieve info about the currently logged in user as well as methods for interacting with it. It sends back an object with the following properties: | Property | Description | | ------------------------ | --------------------------------------------------------------------------------------- | | **`user`** | The currently logged in user | | **`logOut`** | A method to log out the currently logged in user | | **`refreshCookie`** | A method to trigger the silent refreshing of a user's auth token | | **`setToken`** | Set the token of the user, to be decoded and used to reset the user and token in memory | | **`token`** | The logged in user's token (useful for creating preview links, etc.) | | **`refreshPermissions`** | Load new permissions (useful when content that effects permissions has been changed) | | **`permissions`** | The permissions of the current user | ```tsx 'use client' import { useAuth } from '@payloadcms/ui' import type { User } from '../payload-types.ts' const Greeting: React.FC = () => { // highlight-start const { user } = useAuth() // highlight-end return Hi, {user.email}! } ``` ## useConfig Used to retrieve the Payload [Client Config](./components#accessing-the-payload-config). ```tsx 'use client' import { useConfig } from '@payloadcms/ui' const MyComponent: React.FC = () => { // highlight-start const { config } = useConfig() // highlight-end return {config.serverURL} } ``` ## useEditDepth Sends back how many editing levels "deep" the current component is. Edit depth is relevant while adding new documents / editing documents in modal windows and other cases. ```tsx 'use client' import { useEditDepth } from '@payloadcms/ui' const MyComponent: React.FC = () => { // highlight-start const editDepth = useEditDepth() // highlight-end return My component is {editDepth} levels deep } ``` ## usePreferences Returns methods to set and get user preferences. More info can be found [here](https://payloadcms.com/docs/admin/preferences). ## useTheme Returns the currently selected theme (`light`, `dark` or `auto`), a set function to update it and a boolean `autoMode`, used to determine if the theme value should be set automatically based on the user's device preferences. ```tsx 'use client' import { useTheme } from '@payloadcms/ui' const MyComponent: React.FC = () => { // highlight-start const { autoMode, setTheme, theme } = useTheme() // highlight-end return ( <> The current theme is {theme} and autoMode is {autoMode} ) } ``` ## useTableColumns Returns methods to manipulate table columns ```tsx 'use client' import { useTableColumns } from '@payloadcms/ui' const MyComponent: React.FC = () => { // highlight-start const { setActiveColumns } = useTableColumns() const resetColumns = () => { setActiveColumns(['id', 'createdAt', 'updatedAt']) } // highlight-end return ( ) } ``` ## useDocumentEvents The `useDocumentEvents` hook provides a way of subscribing to cross-document events, such as updates made to nested documents within a drawer. This hook will report document events that are outside the scope of the document currently being edited. This hook provides the following: | Property | Description | | ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | | **`mostRecentUpdate`** | An object containing the most recently updated document. It contains the `entitySlug`, `id` (if collection), and `updatedAt` properties | | **`reportUpdate`** | A method used to report updates to documents. It accepts the same arguments as the `mostRecentUpdate` property. | **Example:** ```tsx 'use client' import { useDocumentEvents } from '@payloadcms/ui' const ListenForUpdates: React.FC = () => { const { mostRecentUpdate } = useDocumentEvents() return {JSON.stringify(mostRecentUpdate)} } ``` Right now the `useDocumentEvents` hook only tracks recently updated documents, but in the future it will track more document-related events as needed, such as document creation, deletion, etc.