Fields
Reusable Fields
For fields that occur more than once within the codebase, they should be abstract within src/fields. Every field that
is configurable should accept overrides so the caller can override particular parts of the fieldd.
FAQs Example
1import { ArrayField, deepMerge, Field } from 'payload'
2
3export type FAQsFieldArgs = {
4 overrides?: Partial<Omit<ArrayField, 'type'>>
5}
6
7export const FAQsField = (args?: FAQsFieldArgs): Field => {
8 return deepMerge<ArrayField, Omit<ArrayField, 'type'>>(
9 {
10 name: 'faqs',
11 label: 'FAQs',
12 type: 'array',
13 fields: [
14 {
15 name: 'question',
16 label: 'Question',
17 type: 'text',
18 required: true,
19 admin: {
20 description: 'Add a question for the FAQ item.',
21 },
22 },
23 {
24 name: 'answer',
25 type: 'textarea',
26 label: 'Answer',
27 required: true,
28 admin: {
29 description: 'Add a content (answer) for the FAQ item.',
30 },
31 },
32 ],
33 },
34 args?.overrides || {},
35 )
36}
Slug Example
1export const SlugField: Slug = (fieldToUse = 'title', overrides = {}) => {
2 const checkBoxField = deepMerge<CheckboxField, Partial<CheckboxField>>(
3 {
4 name: 'slugLock',
5 type: 'checkbox',
6 defaultValue: true,
7 admin: {hidden: true, position: 'sidebar'},
8 },
9 checkboxOverrides || {},
10 )
11
12 const slugField = deepMerge<TextField, Partial<TextField>>(
13 {
14 name: 'slug',
15 type: 'text',
16 index: true,
17 unique: true,
18 required: true,
19 hooks: {
20 beforeValidate: [formatSlugHook(fieldToUse)],
21 },
22 admin: {
23 position: 'sidebar',
24 components: {
25 Field: {
26 path: '/fields/Slug/Component#Component',
27 clientProps: {fieldToUse, checkboxFieldPath: checkBoxField.name},
28 },
29 },
30 },
31 },
32 slugOverrides || {},
33 )
34
35 return [slugField, checkBoxField]
36}
Key Patterns
- Use deepMerge for composing field configurations with overrides.
- Provide default values but allow customisation via overrides.
- Co-locate fields that work together (e.g., slug and slugLock).
- Custom components via path references for admin UI customisation.
Width
Use admin.width to control field widths in rows:
1{
2 type: 'row',
3 fields: [
4 {
5 name: 'fieldOne',
6 type: 'text',
7 admin: { width: '50%' },
8 },
9 {
10 name: 'fieldTwo',
11 type: 'text',
12 admin: { width: '50%' },
13 },
14 ],
15}