## Description Threads the field config to all "field subcomponents" through props, i.e. field label, description, error, etc. This way, the field config that controls any particular component is easily accessible and strongly typed, i.e. `props.field.maxLength`. This is true for both server and client components, whose server-side props are now also contextually typed. This behavior was temporarily removed in #7474 due to bloating HTML, but has since been resolved in #7620. This PR also makes significant improvements to component types by exporting explicit types for _every component of every field_, each with its own client/server variation. Now, a custom component can look something like this: ```tsx import type { TextFieldLabelServerComponent } from 'payload' import React from 'react' export const CustomLabel: TextFieldLabelServerComponent = (props) => { return ( <div>{`The max length of this field is: ${props?.field?.maxLength}`}</div> ) } ``` The following types are now available: ```ts import type { TextFieldClientComponent, TextFieldServerComponent, TextFieldLabelClientComponent, TextFieldLabelServerComponent, TextFieldDescriptionClientComponent, TextFieldDescriptionServerComponent, TextFieldErrorClientComponent, TextFieldErrorServerComponent, // ...and so one for each field } from 'payload' ``` BREAKING CHANGES: In order to strictly type these components, a few breaking changes have been made _solely to type definitions_. This only effects you if you are heavily using custom components. Old ```ts import type { ErrorComponent, LabelComponent, DescriptionComponent } from 'payload' ``` New: ```ts import type { FieldErrorClientComponent, FieldErrorServerComponent, FieldLabelClientComponent, FieldLabelServerComponent, FieldDescriptionClientComponent, FieldDescriptionServerComponent, // Note: these are the generic, underlying types of the more stricter types described above ^ // For example, you should use the type that is explicit for your particular field and environment // i.e. `TextFieldLabelClientComponent` and not simply `FieldLabelClientComponent` } from 'payload' ``` - [x] I have read and understand the [CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md) document in this repository. ## Type of change - [x] Bug fix (non-breaking change which fixes an issue) ## Checklist: - [x] I have added tests that prove my fix is effective or that my feature works - [x] Existing test suite passes locally with my changes
590 lines
27 KiB
Plaintext
590 lines
27 KiB
Plaintext
---
|
|
title: Customizing Fields
|
|
label: Customizing Fields
|
|
order: 60
|
|
desc:
|
|
keywords:
|
|
---
|
|
|
|
[Fields](../fields/overview) within the [Admin Panel](./overview) can be endlessly customized in their appearance and behavior without affecting their underlying data structure. Fields are designed to withstand heavy modification or even complete replacement through the use of [Custom Field Components](#field-components), [Conditional Logic](#conditional-logic), [Custom Validations](../fields/overview#validation), and more.
|
|
|
|
For example, your app might need to render a specific interface that Payload does not inherently support, such as a color picker. To do this, you could replace the default [Text Field](../fields/text) input with your own user-friendly component that formats the data into a valid color value.
|
|
|
|
<Banner type="success">
|
|
<strong>Tip:</strong>
|
|
Don't see a built-in field type that you need? Build it! Using a combination of [Field Validations](../fields/overview#validation)
|
|
and [Custom Components](./components), you can override the entirety of how a component functions within the [Admin Panel](./overview) to effectively create your own field type.
|
|
</Banner>
|
|
|
|
## Admin Options
|
|
|
|
You can customize the appearance and behavior of fields within the [Admin Panel](./overview) through the `admin` property of any [Field Config](../fields/overview):
|
|
|
|
```ts
|
|
import type { CollectionConfig } from 'payload'
|
|
|
|
export const CollectionConfig: CollectionConfig = {
|
|
// ...
|
|
fields: [
|
|
// ...
|
|
{
|
|
name: 'myField',
|
|
type: 'text',
|
|
admin: { // highlight-line
|
|
// ...
|
|
},
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
The following options are available:
|
|
|
|
| Option | Description |
|
|
| ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
| **`condition`** | Programmatically show / hide fields based on other fields. [More details](../admin/fields#conditional-logic). |
|
|
| **`components`** | All Field Components can be swapped out for [Custom Components](../admin/components) that you define. [More details](../admin/fields). |
|
|
| **`description`** | Helper text to display alongside the field to provide more information for the editor. [More details](../admin/fields#description). |
|
|
| **`position`** | Specify if the field should be rendered in the sidebar by defining `position: 'sidebar'`. |
|
|
| **`width`** | Restrict the width of a field. You can pass any string-based value here, be it pixels, percentages, etc. This property is especially useful when fields are nested within a `Row` type where they can be organized horizontally. |
|
|
| **`style`** | [CSS Properties](https://developer.mozilla.org/en-US/docs/Web/CSS) to inject into the root element of the field. |
|
|
| **`className`** | Attach a [CSS class attribute](https://developer.mozilla.org/en-US/docs/Web/CSS/Class_selectors) to the root DOM element of a field. |
|
|
| **`readOnly`** | Setting a field to `readOnly` has no effect on the API whatsoever but disables the admin component's editability to prevent editors from modifying the field's value. |
|
|
| **`disabled`** | If a field is `disabled`, it is completely omitted from the [Admin Panel](../admin/overview). |
|
|
| **`disableBulkEdit`** | Set `disableBulkEdit` to `true` to prevent fields from appearing in the select options when making edits for multiple documents. |
|
|
| **`disableListColumn`** | Set `disableListColumn` to `true` to prevent fields from appearing in the list view column selector. |
|
|
| **`disableListFilter`** | Set `disableListFilter` to `true` to prevent fields from appearing in the list view filter options. |
|
|
| **`hidden`** | Will transform the field into a `hidden` input type. Its value will still submit with requests in the Admin Panel, but the field itself will not be visible to editors. |
|
|
|
|
## Field Components
|
|
|
|
Within the [Admin Panel](./overview), fields are rendered in three distinct places:
|
|
|
|
- [Field](#the-field-component) - The actual form field rendered in the Edit View.
|
|
- [Cell](#the-cell-component) - The table cell component rendered in the List View.
|
|
- [Filter](#the-filter-component) - The filter component rendered in the List View.
|
|
|
|
To easily swap in Field Components with your own, use the `admin.components` property in your [Field Config](../fields/overview):
|
|
|
|
```ts
|
|
import type { CollectionConfig } from 'payload'
|
|
|
|
export const CollectionConfig: CollectionConfig = {
|
|
// ...
|
|
fields: [
|
|
// ...
|
|
{
|
|
// ...
|
|
admin: {
|
|
components: { // highlight-line
|
|
// ...
|
|
},
|
|
},
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
The following options are available:
|
|
|
|
| Component | Description |
|
|
| ---------- | --------------------------------------------------------------------------------------------------------------------------- |
|
|
| **`Field`** | The form field rendered of the Edit View. [More details](#the-field-component). |
|
|
| **`Cell`** | The table cell rendered of the List View. [More details](#the-cell-component). |
|
|
| **`Filter`** | The filter component rendered in the List View. [More details](#the-filter-component). || Component | Description |
|
|
| **`Label`** | Override the default Label of the Field Component. [More details](#the-label-component). |
|
|
| **`Error`** | Override the default Error of the Field Component. [More details](#the-error-component). |
|
|
| **`Description`** | Override the default Description of the Field Component. [More details](#the-description-component). |
|
|
| **`beforeInput`** | An array of elements that will be added before the input of the Field Component. [More details](#afterinput-and-beforeinput).|
|
|
| **`afterInput`** | An array of elements that will be added after the input of the Field Component. [More details](#afterinput-and-beforeinput). |
|
|
|
|
_\* **`beforeInput`** and **`afterInput`** are only supported in fields that do not contain other fields, such as [`Text`](../fields/text), and [`Textarea`](../fields/textarea)._
|
|
|
|
### The Field Component
|
|
|
|
The Field Component is the actual form field rendered in the Edit View. This is the input that user's will interact with when editing a document.
|
|
|
|
To easily swap in your own Field Component, use the `admin.components.Field` property in your [Field Config](../fields/overview):
|
|
|
|
```ts
|
|
import type { CollectionConfig } from 'payload'
|
|
|
|
export const CollectionConfig: CollectionConfig = {
|
|
// ...
|
|
fields: [
|
|
// ...
|
|
{
|
|
// ...
|
|
admin: {
|
|
components: {
|
|
Field: '/path/to/MyFieldComponent', // highlight-line
|
|
},
|
|
},
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
_For details on how to build Custom Components, see [Building Custom Components](./components#building-custom-components)._
|
|
|
|
<Banner type="warning">
|
|
Instead of replacing the entire Field Component, you can alternately replace or slot-in only specific parts by using the [`Label`](#the-label-component), [`Error`](#the-error-component), [`beforeInput`](#afterinput-and-beforinput), and [`afterInput`](#afterinput-and-beforinput) properties.
|
|
</Banner>
|
|
|
|
All Field Components receive the following props:
|
|
|
|
| Property | Description |
|
|
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
| **`docPreferences`** | An object that contains the [Preferences](./preferences) for the document.
|
|
| **`field`** | The sanitized, client-friendly version of the field's config. [More details](#the-field-prop) |
|
|
| **`locale`** | The locale of the field. [More details](../configuration/localization). |
|
|
| **`readOnly`** | A boolean value that represents if the field is read-only or not. |
|
|
| **`user`** | The currently authenticated user. [More details](../authentication/overview). |
|
|
| **`validate`** | A function that can be used to validate the field. |
|
|
|
|
<Banner type="success">
|
|
<strong>Reminder:</strong>
|
|
All [Custom Server Components](./components) receive the `payload` and `i18n` properties by default. See [Building Custom Components](./components#building-custom-components) for more details.
|
|
</Banner>
|
|
|
|
#### Sending and receiving values from the form
|
|
|
|
When swapping out the `Field` component, you are responsible for sending and receiving the field's `value` from the form itself.
|
|
|
|
To do so, import the [`useField`](./hooks#usefield) hook from `@payloadcms/ui` and use it to manage the field's value:
|
|
|
|
```tsx
|
|
'use client'
|
|
import { useField } from '@payloadcms/ui'
|
|
|
|
export const CustomTextField: React.FC = () => {
|
|
const { value, setValue } = useField() // highlight-line
|
|
|
|
return (
|
|
<input
|
|
onChange={(e) => setValue(e.target.value)}
|
|
value={value}
|
|
/>
|
|
)
|
|
}
|
|
```
|
|
|
|
<Banner type="success">
|
|
For a complete list of all available React hooks, see the [Payload React Hooks](./hooks) documentation. For additional help, see [Building Custom Components](./components#building-custom-components).
|
|
</Banner>
|
|
|
|
#### TypeScript
|
|
|
|
When building Custom Field Components, you can import the component props to ensure type safety in your component. There is an explicit type for the Field Component, one for every [Field Type](../fields/overview). The convention is to append `Props` to the type of field, i.e. `TextFieldProps`.
|
|
|
|
```tsx
|
|
import type {
|
|
ArrayFieldProps,
|
|
BlocksFieldProps,
|
|
CheckboxFieldProps,
|
|
CodeFieldProps,
|
|
CollapsibleFieldProps,
|
|
DateFieldProps,
|
|
EmailFieldProps,
|
|
GroupFieldProps,
|
|
HiddenFieldProps,
|
|
JSONFieldProps,
|
|
NumberFieldProps,
|
|
PointFieldProps,
|
|
RadioFieldProps,
|
|
RelationshipFieldProps,
|
|
RichTextFieldProps,
|
|
RowFieldProps,
|
|
SelectFieldProps,
|
|
TabsFieldProps,
|
|
TextFieldProps,
|
|
TextareaFieldProps,
|
|
UploadFieldProps
|
|
} from 'payload'
|
|
```
|
|
|
|
### The `field` Prop
|
|
|
|
All Field Components are passed a client-friendly version of their Field Config through a common `field` prop. Since the raw Field Config is [non-serializable](https://react.dev/reference/rsc/use-client#serializable-types), Payload sanitized it into a [Client Config](./components#accessing-the-payload-config) that is safe to pass into Client Components.
|
|
|
|
The exact shape of this prop is unique to the specific [Field Type](../fields/overview) being rendered, minus all non-serializable properties. Any [Custom Components](../components) are also resolved into a "mapped component" that is safe to pass.
|
|
|
|
```tsx
|
|
'use client'
|
|
import React from 'react'
|
|
import type { TextFieldProps } from 'payload'
|
|
|
|
export const MyClientFieldComponent: React.FC<TextFieldProps> = ({ field: { name } }) => {
|
|
return (
|
|
<p>
|
|
{`This field's name is ${name}`}
|
|
</p>
|
|
)
|
|
}
|
|
```
|
|
|
|
The following additional properties are also provided to the `field` prop:
|
|
|
|
| Property | Description |
|
|
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
| **`_isPresentational`** | A boolean indicating that the field is purely visual and does not directly affect data or change data shape, i.e. the [UI Field](../fields/ui). |
|
|
| **`_path`** | A string representing the direct, dynamic path to the field at runtime, i.e. `myGroup.myArray[0].myField`. |
|
|
| **`_schemaPath`** | A string representing the direct, static path to the [Field Config](../fields/overview), i.e. `myGroup.myArray.myField` |
|
|
|
|
<Banner type="info">
|
|
<strong>Note:</strong>
|
|
These properties are underscored to denote that they are not part of the original Field Config, and instead are attached during client sanitization to make fields easier to work with on the front-end.
|
|
</Banner>
|
|
|
|
#### TypeScript
|
|
|
|
When building Custom Field Components, you can import the client field props to ensure type safety in your component. There is an explicit type for the Field Component, one for every [Field Type](../fields/overview). The convention is to append `Client` to the type of field, i.e. `TextFieldClient`.
|
|
|
|
```tsx
|
|
import type {
|
|
ArrayFieldClient,
|
|
BlocksFieldClient,
|
|
CheckboxFieldClient,
|
|
CodeFieldClient,
|
|
CollapsibleFieldClient,
|
|
DateFieldClient,
|
|
EmailFieldClient,
|
|
GroupFieldClient,
|
|
HiddenFieldClient,
|
|
JSONFieldClient,
|
|
NumberFieldClient,
|
|
PointFieldClient,
|
|
RadioFieldClient,
|
|
RelationshipFieldClient,
|
|
RichTextFieldClient,
|
|
RowFieldClient,
|
|
SelectFieldClient,
|
|
TabsFieldClient,
|
|
TextFieldClient,
|
|
TextareaFieldClient,
|
|
UploadFieldClient
|
|
} from 'payload'
|
|
```
|
|
|
|
When working on the client, you will never have access to objects of type `Field`. This is reserved for the server-side. Instead, you can use `ClientField` which is a union type of all the client fields:
|
|
|
|
```tsx
|
|
import type { ClientField } from 'payload'
|
|
```
|
|
|
|
### The Cell Component
|
|
|
|
The Cell Component is rendered in the table of the List View. It represents the value of the field when displayed in a table cell.
|
|
|
|
To easily swap in your own Cell Component, use the `admin.components.Cell` property in your [Field Config](../fields/overview):
|
|
|
|
```ts
|
|
import type { Field } from 'payload'
|
|
|
|
export const myField: Field = {
|
|
name: 'myField',
|
|
type: 'text',
|
|
admin: {
|
|
components: {
|
|
Cell: '/path/to/MyCustomCellComponent', // highlight-line
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
_For details on how to build Custom Components, see [Building Custom Components](./components#building-custom-components)._
|
|
|
|
All Cell Components receive the following props:
|
|
|
|
| Property | Description |
|
|
| ---------------- | ----------------------------------------------------------------- |
|
|
| **`field`** | The sanitized, client-friendly version of the field's config. [More details](#the-field-prop) |
|
|
| **`link`** | A boolean representing whether this cell should be wrapped in a link. |
|
|
| **`onClick`** | A function that is called when the cell is clicked. |
|
|
|
|
<Banner type="info">
|
|
<strong>Tip:</strong>
|
|
Use the [`useTableCell`](./hooks#usetablecell) hook to subscribe to the field's `cellData` and `rowData`.
|
|
</Banner>
|
|
|
|
<Banner type="success">
|
|
<strong>Reminder:</strong>
|
|
All [Custom Server Components](./components) receive the `payload` and `i18n` properties by default. See [Building Custom Components](./components#building-custom-components) for more details.
|
|
</Banner>
|
|
|
|
### The Label Component
|
|
|
|
The Label Component is rendered anywhere a field needs to be represented by a label. This is typically used in the Edit View, but can also be used in the List View and elsewhere.
|
|
|
|
To easily swap in your own Label Component, use the `admin.components.Label` property in your [Field Config](../fields/overview):
|
|
|
|
```ts
|
|
import type { Field } from 'payload'
|
|
|
|
export const myField: Field = {
|
|
name: 'myField',
|
|
type: 'text',
|
|
admin: {
|
|
components: {
|
|
Label: '/path/to/MyCustomLabelComponent', // highlight-line
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
_For details on how to build Custom Components, see [Building Custom Components](./components#building-custom-components)._
|
|
|
|
Custom Label Components receive all [Field Component](#the-field-component) props, plus the following props:
|
|
|
|
| Property | Description |
|
|
| -------------- | ---------------------------------------------------------------- |
|
|
| **`field`** | The sanitized, client-friendly version of the field's config. [More details](#the-field-prop) |
|
|
|
|
<Banner type="success">
|
|
<strong>Reminder:</strong>
|
|
All [Custom Server Components](./components) receive the `payload` and `i18n` properties by default. See [Building Custom Components](./components#building-custom-components) for more details.
|
|
</Banner>
|
|
|
|
#### TypeScript
|
|
|
|
When building Custom Label Components, you can import the component props to ensure type safety in your component. There is an explicit type for the Label Component, one for every [Field Type](../fields/overview) and server/client environment. The convention is to append `LabelServerComponent` or `LabelClientComponent` to the type of field, i.e. `TextFieldLabelClientComponent`.
|
|
|
|
```tsx
|
|
import type {
|
|
TextFieldLabelServerComponent,
|
|
TextFieldLabelClientComponent,
|
|
// And so on for each Field Type
|
|
} from 'payload'
|
|
```
|
|
|
|
### The Error Component
|
|
|
|
The Error Component is rendered when a field fails validation. It is typically displayed beneath the field input in a visually-compelling style.
|
|
|
|
To easily swap in your own Error Component, use the `admin.components.Error` property in your [Field Config](../fields/overview):
|
|
|
|
```ts
|
|
import type { Field } from 'payload'
|
|
|
|
export const myField: Field = {
|
|
name: 'myField',
|
|
type: 'text',
|
|
admin: {
|
|
components: {
|
|
Error: '/path/to/MyCustomErrorComponent', // highlight-line
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
_For details on how to build Custom Components, see [Building Custom Components](./components#building-custom-components)._
|
|
|
|
Custom Error Components receive all [Field Component](#the-field-component) props, plus the following props:
|
|
|
|
| Property | Description |
|
|
| --------------- | ------------------------------------------------------------- |
|
|
| **`field`** | The sanitized, client-friendly version of the field's config. [More details](#the-field-prop) |
|
|
|
|
<Banner type="success">
|
|
<strong>Reminder:</strong>
|
|
All [Custom Server Components](./components) receive the `payload` and `i18n` properties by default. See [Building Custom Components](./components#building-custom-components) for more details.
|
|
</Banner>
|
|
|
|
#### TypeScript
|
|
|
|
When building Custom Error Components, you can import the component props to ensure type safety in your component. There is an explicit type for the Error Component, one for every [Field Type](../fields/overview) and server/client environment. The convention is to append `ErrorServerComponent` or `ErrorClientComponent` to the type of field, i.e. `TextFieldErrorClientComponent`.
|
|
|
|
```tsx
|
|
import type {
|
|
TextFieldErrorServerComponent,
|
|
TextFieldErrorClientComponent,
|
|
// And so on for each Field Type
|
|
} from 'payload'
|
|
```
|
|
|
|
### The Description Property
|
|
|
|
Field Descriptions are used to provide additional information to the editor about a field, such as special instructions. Their placement varies from field to field, but typically are displayed with subtle style differences beneath the field inputs.
|
|
|
|
A description can be configured in three ways:
|
|
|
|
- As a string.
|
|
- As a function which returns a string. [More details](#description-functions).
|
|
- As a React component. [More details](#the-description-component).
|
|
|
|
To easily add a Custom Description to a field, use the `admin.description` property in your [Field Config](../fields/overview):
|
|
|
|
```ts
|
|
import type { SanitizedCollectionConfig } from 'payload'
|
|
|
|
export const MyCollectionConfig: SanitizedCollectionConfig = {
|
|
// ...
|
|
fields: [
|
|
// ...
|
|
{
|
|
name: 'myField',
|
|
type: 'text',
|
|
admin: {
|
|
description: 'Hello, world!' // highlight-line
|
|
},
|
|
},
|
|
]
|
|
}
|
|
```
|
|
|
|
<Banner type="warning">
|
|
<strong>Reminder:</strong>
|
|
To replace the Field Description with a [Custom Component](./components), use the `admin.components.Description` property. [More details](#the-description-component).
|
|
</Banner>
|
|
|
|
#### Description Functions
|
|
|
|
Custom Descriptions can also be defined as a function. Description Functions are executed on the server and can be used to format simple descriptions based on the user's current [Locale](../configuration/localization).
|
|
|
|
To easily add a Description Function to a field, set the `admin.description` property to a _function_ in your [Field Config](../fields/overview):
|
|
|
|
```ts
|
|
import type { SanitizedCollectionConfig } from 'payload'
|
|
|
|
export const MyCollectionConfig: SanitizedCollectionConfig = {
|
|
// ...
|
|
fields: [
|
|
// ...
|
|
{
|
|
name: 'myField',
|
|
type: 'text',
|
|
admin: {
|
|
description: ({ t }) => `${t('Hello, world!')}` // highlight-line
|
|
},
|
|
},
|
|
]
|
|
}
|
|
```
|
|
|
|
All Description Functions receive the following arguments:
|
|
|
|
| Argument | Description |
|
|
| -------------- | ---------------------------------------------------------------- |
|
|
| **`t`** | The `t` function used to internationalize the Admin Panel. [More details](../configuration/i18n) |
|
|
|
|
### The Description Component
|
|
|
|
Alternatively to the [Description Property](#the-description-property), you can also use a [Custom Component](./components) as the Field Description. This can be useful when you need to provide more complex feedback to the user, such as rendering dynamic field values or other interactive elements.
|
|
|
|
To easily add a Description Component to a field, use the `admin.components.Description` property in your [Field Config](../fields/overview):
|
|
|
|
```ts
|
|
import type { SanitizedCollectionConfig } from 'payload'
|
|
|
|
export const MyCollectionConfig: SanitizedCollectionConfig = {
|
|
// ...
|
|
fields: [
|
|
// ...
|
|
{
|
|
name: 'myField',
|
|
type: 'text',
|
|
admin: {
|
|
components: {
|
|
Description: '/path/to/MyCustomDescriptionComponent', // highlight-line
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
_For details on how to build a Custom Description, see [Building Custom Components](./components#building-custom-components)._
|
|
|
|
Custom Description Components receive all [Field Component](#the-field-component) props, plus the following props:
|
|
|
|
| Property | Description |
|
|
| -------------- | ---------------------------------------------------------------- |
|
|
| **`field`** | The sanitized, client-friendly version of the field's config. [More details](#the-field-prop) |
|
|
|
|
<Banner type="success">
|
|
<strong>Reminder:</strong>
|
|
All [Custom Server Components](./components) receive the `payload` and `i18n` properties by default. See [Building Custom Components](./components#building-custom-components) for more details.
|
|
</Banner>
|
|
|
|
#### TypeScript
|
|
|
|
When building Custom Description Components, you can import the component props to ensure type safety in your component. There is an explicit type for the Description Component, one for every [Field Type](../fields/overview) and server/client environment. The convention is to append `DescriptionServerComponent` or `DescriptionClientComponent` to the type of field, i.e. `TextFieldDescriptionClientComponent`.
|
|
|
|
```tsx
|
|
import type {
|
|
TextFieldDescriptionServerComponent,
|
|
TextFieldDescriptionClientComponent,
|
|
// And so on for each Field Type
|
|
} from 'payload'
|
|
```
|
|
|
|
### afterInput and beforeInput
|
|
|
|
With these properties you can add multiple components _before_ and _after_ the input element, as their name suggests. This is useful when you need to render additional elements alongside the field without replacing the entire field component.
|
|
|
|
To add components before and after the input element, use the `admin.components.beforeInput` and `admin.components.afterInput` properties in your [Field Config](../fields/overview):
|
|
|
|
```ts
|
|
import type { SanitizedCollectionConfig } from 'payload'
|
|
|
|
export const MyCollectionConfig: SanitizedCollectionConfig = {
|
|
// ...
|
|
fields: [
|
|
// ...
|
|
{
|
|
name: 'myField',
|
|
type: 'text',
|
|
admin: {
|
|
components: {
|
|
// highlight-start
|
|
beforeInput: ['/path/to/MyCustomComponent'],
|
|
afterInput: ['/path/to/MyOtherCustomComponent'],
|
|
// highlight-end
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
_For details on how to build Custom Components, see [Building Custom Components](./components#building-custom-components)._
|
|
|
|
## Conditional Logic
|
|
|
|
You can show and hide fields based on what other fields are doing by utilizing conditional logic on a field by field basis. The `condition` property on a field's admin config accepts a function which takes three arguments:
|
|
|
|
- `data` - the entire document's data that is currently being edited
|
|
- `siblingData` - only the fields that are direct siblings to the field with the condition
|
|
- `{ user }` - the final argument is an object containing the currently authenticated user
|
|
|
|
The `condition` function should return a boolean that will control if the field should be displayed or not.
|
|
|
|
**Example:**
|
|
|
|
```ts
|
|
{
|
|
fields: [
|
|
{
|
|
name: 'enableGreeting',
|
|
type: 'checkbox',
|
|
defaultValue: false,
|
|
},
|
|
{
|
|
name: 'greeting',
|
|
type: 'text',
|
|
admin: {
|
|
// highlight-start
|
|
condition: (data, siblingData, { user }) => {
|
|
if (data.enableGreeting) {
|
|
return true
|
|
} else {
|
|
return false
|
|
}
|
|
},
|
|
// highlight-end
|
|
},
|
|
},
|
|
]
|
|
}
|
|
```
|