0
# Field Types
1
2
Rich set of field types for modeling content including text fields, relationships, file uploads, rich text editing, and complex nested structures. Fields are the building blocks of your content model in Payload.
3
4
## Capabilities
5
6
### Text Fields
7
8
Basic text input fields for short text content.
9
10
```typescript { .api }
11
interface TextField extends BaseField {
12
type: 'text';
13
/** Maximum character length */
14
maxLength?: number;
15
/** Minimum character length */
16
minLength?: number;
17
/** Allow multiple values (array) */
18
hasMany?: boolean;
19
}
20
```
21
22
**Usage Example:**
23
24
```typescript
25
const titleField: TextField = {
26
name: "title",
27
type: "text",
28
label: "Post Title",
29
required: true,
30
maxLength: 100,
31
admin: {
32
placeholder: "Enter post title...",
33
},
34
};
35
36
// Multi-value text field
37
const tagsField: TextField = {
38
name: "tags",
39
type: "text",
40
hasMany: true,
41
admin: {
42
placeholder: "Add tags...",
43
},
44
};
45
```
46
47
### Rich Text Fields
48
49
Advanced text editor with formatting, blocks, and custom elements.
50
51
```typescript { .api }
52
interface RichTextField extends BaseField {
53
type: 'richText';
54
/** Rich text editor configuration */
55
editor?: RichTextEditorConfig;
56
}
57
58
interface RichTextEditorConfig {
59
/** Custom elements (bold, italic, etc.) */
60
elements?: RichTextElement[];
61
/** Custom leaves (inline formatting) */
62
leaves?: RichTextLeaf[];
63
/** Upload collections for media */
64
upload?: {
65
collections: {
66
[collectionSlug: string]: UploadConfig;
67
};
68
};
69
/** Link configuration */
70
link?: {
71
/** Collections that can be linked to */
72
collections?: string[];
73
/** External URL linking */
74
url?: boolean;
75
};
76
}
77
```
78
79
**Usage Example:**
80
81
```typescript
82
const contentField: RichTextField = {
83
name: "content",
84
type: "richText",
85
label: "Post Content",
86
required: true,
87
editor: {
88
elements: ["h2", "h3", "blockquote", "ul", "ol", "link"],
89
leaves: ["bold", "italic", "underline", "code"],
90
upload: {
91
collections: {
92
media: {
93
fields: [],
94
},
95
},
96
},
97
link: {
98
collections: ["posts", "pages"],
99
url: true,
100
},
101
},
102
};
103
```
104
105
### Number Fields
106
107
Numeric input fields with validation and formatting options.
108
109
```typescript { .api }
110
interface NumberField extends BaseField {
111
type: 'number';
112
/** Minimum value */
113
min?: number;
114
/** Maximum value */
115
max?: number;
116
/** Allow multiple values (array) */
117
hasMany?: boolean;
118
}
119
```
120
121
**Usage Example:**
122
123
```typescript
124
const priceField: NumberField = {
125
name: "price",
126
type: "number",
127
label: "Price",
128
required: true,
129
min: 0,
130
max: 10000,
131
admin: {
132
step: 0.01,
133
placeholder: "0.00",
134
},
135
};
136
```
137
138
### Select Fields
139
140
Dropdown selection fields with predefined options.
141
142
```typescript { .api }
143
interface SelectField extends BaseField {
144
type: 'select';
145
/** Available options */
146
options: Option[];
147
/** Allow multiple selections */
148
hasMany?: boolean;
149
}
150
151
interface Option {
152
/** Display label */
153
label: string;
154
/** Stored value */
155
value: string;
156
}
157
```
158
159
**Usage Example:**
160
161
```typescript
162
const statusField: SelectField = {
163
name: "status",
164
type: "select",
165
label: "Status",
166
required: true,
167
options: [
168
{ label: "Draft", value: "draft" },
169
{ label: "Published", value: "published" },
170
{ label: "Archived", value: "archived" },
171
],
172
defaultValue: "draft",
173
};
174
175
// Multi-select field
176
const categoriesField: SelectField = {
177
name: "categories",
178
type: "select",
179
hasMany: true,
180
options: [
181
{ label: "Technology", value: "tech" },
182
{ label: "Design", value: "design" },
183
{ label: "Business", value: "business" },
184
],
185
};
186
```
187
188
### Relationship Fields
189
190
Reference other documents within collections.
191
192
```typescript { .api }
193
interface RelationshipField extends BaseField {
194
type: 'relationship';
195
/** Collection(s) to relate to */
196
relationTo: string | string[];
197
/** Allow multiple relationships */
198
hasMany?: boolean;
199
/** Maximum depth for population */
200
maxDepth?: number;
201
}
202
```
203
204
**Usage Example:**
205
206
```typescript
207
// Single relationship
208
const authorField: RelationshipField = {
209
name: "author",
210
type: "relationship",
211
relationTo: "users",
212
required: true,
213
admin: {
214
position: "sidebar",
215
},
216
};
217
218
// Multiple relationships to different collections
219
const relatedContentField: RelationshipField = {
220
name: "relatedContent",
221
type: "relationship",
222
relationTo: ["posts", "pages", "products"],
223
hasMany: true,
224
maxDepth: 1,
225
};
226
227
// Multiple relationships to same collection
228
const relatedPostsField: RelationshipField = {
229
name: "relatedPosts",
230
type: "relationship",
231
relationTo: "posts",
232
hasMany: true,
233
filterOptions: ({ data }) => {
234
return {
235
id: {
236
not_in: [data.id],
237
},
238
};
239
},
240
};
241
```
242
243
### Upload Fields
244
245
File upload fields for media and documents.
246
247
```typescript { .api }
248
interface UploadField extends BaseField {
249
type: 'upload';
250
/** Upload collection to relate to */
251
relationTo: string;
252
}
253
```
254
255
**Usage Example:**
256
257
```typescript
258
const featuredImageField: UploadField = {
259
name: "featuredImage",
260
type: "upload",
261
relationTo: "media",
262
admin: {
263
description: "Choose a featured image for this post",
264
},
265
};
266
267
// Multiple file uploads
268
const galleryField: UploadField = {
269
name: "gallery",
270
type: "upload",
271
relationTo: "media",
272
hasMany: true,
273
};
274
```
275
276
### Array Fields
277
278
Repeatable field groups for complex data structures.
279
280
```typescript { .api }
281
interface ArrayField extends BaseField {
282
type: 'array';
283
/** Fields within each array item */
284
fields: Field[];
285
/** Minimum number of items */
286
minRows?: number;
287
/** Maximum number of items */
288
maxRows?: number;
289
/** Labels for admin interface */
290
labels?: {
291
singular?: string;
292
plural?: string;
293
};
294
}
295
```
296
297
**Usage Example:**
298
299
```typescript
300
const testimonialsField: ArrayField = {
301
name: "testimonials",
302
type: "array",
303
label: "Testimonials",
304
minRows: 1,
305
maxRows: 10,
306
labels: {
307
singular: "Testimonial",
308
plural: "Testimonials",
309
},
310
fields: [
311
{
312
name: "quote",
313
type: "textarea",
314
required: true,
315
},
316
{
317
name: "author",
318
type: "text",
319
required: true,
320
},
321
{
322
name: "company",
323
type: "text",
324
},
325
{
326
name: "photo",
327
type: "upload",
328
relationTo: "media",
329
},
330
],
331
};
332
```
333
334
### Block Fields
335
336
Flexible content blocks for page builders and dynamic layouts.
337
338
```typescript { .api }
339
interface BlockField extends BaseField {
340
type: 'blocks';
341
/** Available block types */
342
blocks: Block[];
343
/** Minimum number of blocks */
344
minRows?: number;
345
/** Maximum number of blocks */
346
maxRows?: number;
347
/** Labels for admin interface */
348
labels?: {
349
singular?: string;
350
plural?: string;
351
};
352
}
353
354
interface Block {
355
/** Unique block identifier */
356
slug: string;
357
/** Display label */
358
label?: string;
359
/** Block fields */
360
fields: Field[];
361
/** Admin configuration */
362
admin?: {
363
condition?: (data: any, siblingData: any) => boolean;
364
};
365
/** GraphQL configuration */
366
graphQL?: {
367
singularName?: string;
368
};
369
}
370
```
371
372
**Usage Example:**
373
374
```typescript
375
const pageContentField: BlockField = {
376
name: "layout",
377
type: "blocks",
378
label: "Page Layout",
379
minRows: 1,
380
blocks: [
381
{
382
slug: "hero",
383
label: "Hero Section",
384
fields: [
385
{
386
name: "headline",
387
type: "text",
388
required: true,
389
},
390
{
391
name: "subheading",
392
type: "textarea",
393
},
394
{
395
name: "backgroundImage",
396
type: "upload",
397
relationTo: "media",
398
},
399
],
400
},
401
{
402
slug: "content",
403
label: "Content Block",
404
fields: [
405
{
406
name: "content",
407
type: "richText",
408
required: true,
409
},
410
],
411
},
412
{
413
slug: "gallery",
414
label: "Image Gallery",
415
fields: [
416
{
417
name: "images",
418
type: "array",
419
fields: [
420
{
421
name: "image",
422
type: "upload",
423
relationTo: "media",
424
required: true,
425
},
426
{
427
name: "caption",
428
type: "text",
429
},
430
],
431
},
432
],
433
},
434
],
435
};
436
```
437
438
### Group Fields
439
440
Organize related fields together for better admin UX.
441
442
```typescript { .api }
443
interface GroupField extends BaseField {
444
type: 'group';
445
/** Fields within the group */
446
fields: Field[];
447
}
448
```
449
450
**Usage Example:**
451
452
```typescript
453
const seoField: GroupField = {
454
name: "seo",
455
type: "group",
456
label: "SEO Settings",
457
fields: [
458
{
459
name: "title",
460
type: "text",
461
maxLength: 60,
462
},
463
{
464
name: "description",
465
type: "textarea",
466
maxLength: 160,
467
},
468
{
469
name: "keywords",
470
type: "text",
471
hasMany: true,
472
},
473
{
474
name: "ogImage",
475
type: "upload",
476
relationTo: "media",
477
},
478
],
479
admin: {
480
condition: (data, siblingData) => {
481
return data.status === "published";
482
},
483
},
484
};
485
```
486
487
### Other Field Types
488
489
Additional field types for specific use cases.
490
491
```typescript { .api }
492
// Email field with validation
493
interface EmailField extends BaseField {
494
type: 'email';
495
hasMany?: boolean;
496
}
497
498
// Textarea for longer text
499
interface TextareaField extends BaseField {
500
type: 'textarea';
501
maxLength?: number;
502
minLength?: number;
503
rows?: number;
504
}
505
506
// Checkbox for boolean values
507
interface CheckboxField extends BaseField {
508
type: 'checkbox';
509
}
510
511
// Date picker field
512
interface DateField extends BaseField {
513
type: 'date';
514
displayFormat?: string;
515
pickerAppearance?: 'dayAndTime' | 'timeOnly' | 'dayOnly' | 'monthOnly';
516
}
517
518
// Code editor field
519
interface CodeField extends BaseField {
520
type: 'code';
521
language?: string;
522
}
523
524
// Geographic point field
525
interface PointField extends BaseField {
526
type: 'point';
527
}
528
529
// Radio button group
530
interface RadioField extends BaseField {
531
type: 'radio';
532
options: Option[];
533
}
534
535
// Row field for horizontal layout
536
interface RowField extends BaseField {
537
type: 'row';
538
fields: Field[];
539
}
540
541
// Collapsible field container
542
interface CollapsibleField extends BaseField {
543
type: 'collapsible';
544
label: string;
545
fields: Field[];
546
}
547
548
// Tabbed field interface
549
interface TabsField extends BaseField {
550
type: 'tabs';
551
tabs: Tab[];
552
}
553
554
interface Tab {
555
label: string;
556
description?: string;
557
fields: Field[];
558
}
559
560
// UI field for custom components
561
interface UIField extends BaseField {
562
type: 'ui';
563
admin: {
564
components?: {
565
Field?: React.ComponentType;
566
Cell?: React.ComponentType;
567
};
568
};
569
}
570
```
571
572
## Base Field Interface
573
574
All fields extend the base field interface with common properties.
575
576
```typescript { .api }
577
interface BaseField {
578
/** Field name (becomes database field name) */
579
name: string;
580
/** Field type */
581
type: string;
582
/** Display label */
583
label?: string;
584
/** Whether field is required */
585
required?: boolean;
586
/** Default value */
587
defaultValue?: any;
588
/** Validation function */
589
validate?: Validate;
590
/** Field-level access control */
591
access?: FieldAccess;
592
/** Field-level hooks */
593
hooks?: FieldHooks;
594
/** Admin interface configuration */
595
admin?: FieldAdminConfig;
596
/** Localization configuration */
597
localized?: boolean;
598
/** Custom condition for field visibility */
599
condition?: (data: any, siblingData: any) => boolean;
600
/** Database index configuration */
601
index?: boolean;
602
/** Save field to database */
603
saveToJWT?: boolean;
604
/** Hide field from GraphQL schema */
605
hidden?: boolean;
606
}
607
608
interface FieldAccess {
609
read?: AccessFunction;
610
create?: AccessFunction;
611
update?: AccessFunction;
612
}
613
614
interface FieldAdminConfig {
615
/** Field position in admin */
616
position?: "sidebar";
617
/** Field description */
618
description?: string;
619
/** Placeholder text */
620
placeholder?: string;
621
/** Field width */
622
width?: string;
623
/** Custom field component */
624
components?: {
625
Field?: React.ComponentType;
626
Cell?: React.ComponentType;
627
};
628
/** Hide field in admin */
629
hidden?: boolean;
630
/** Make field read-only */
631
readOnly?: boolean;
632
/** Conditional field display */
633
condition?: (data: any, siblingData: any) => boolean;
634
}
635
636
type Validate = (
637
value: any,
638
args: {
639
data: any;
640
siblingData: any;
641
user: User;
642
operation: "create" | "update";
643
}
644
) => true | string | Promise<true | string>;
645
```
646
647
## Upload Configuration
648
649
### File Upload Configuration
650
651
Comprehensive file upload and image processing configuration for collections with upload capabilities.
652
653
```typescript { .api }
654
/**
655
* Upload configuration for collections
656
*/
657
interface UploadConfig {
658
/** Image size variants to generate */
659
imageSizes?: ImageSize[];
660
/** URL path for serving static files */
661
staticURL: string;
662
/** Directory path for storing files */
663
staticDir: string;
664
/** Disable local file storage (for cloud storage) */
665
disableLocalStorage: boolean;
666
/** Thumbnail configuration for admin */
667
adminThumbnail?: string | GetAdminThumbnail;
668
/** Allowed MIME types */
669
mimeTypes?: string[];
670
/** Express static file serving options */
671
staticOptions?: ServeStaticOptions;
672
/** Custom upload handlers */
673
handlers?: UploadHandler[];
674
/** Global image resize options */
675
resizeOptions?: ResizeOptions;
676
/** Global image format options */
677
formatOptions?: ImageUploadFormatOptions;
678
}
679
680
/**
681
* Image size configuration for automatic variants
682
*/
683
interface ImageSize {
684
/** Size variant name */
685
name: string;
686
/** Image width */
687
width?: number;
688
/** Image height */
689
height?: number;
690
/** Resize fit mode */
691
fit?: 'cover' | 'contain' | 'fill' | 'inside' | 'outside';
692
/** Resize position/gravity */
693
position?: 'top' | 'right top' | 'right' | 'right bottom' | 'bottom' | 'left bottom' | 'left' | 'left top' | 'center';
694
/** Format options for this size */
695
formatOptions?: ImageUploadFormatOptions;
696
/** @deprecated Use position instead */
697
crop?: string;
698
}
699
700
/**
701
* Image format conversion options
702
*/
703
interface ImageUploadFormatOptions {
704
/** Target image format */
705
format: 'jpeg' | 'png' | 'webp' | 'avif' | 'tiff';
706
/** Format-specific options */
707
options?: {
708
/** JPEG quality (1-100) */
709
quality?: number;
710
/** PNG compression level (0-9) */
711
compressionLevel?: number;
712
/** WebP quality (1-100) */
713
quality?: number;
714
/** Enable progressive encoding */
715
progressive?: boolean;
716
};
717
}
718
719
/**
720
* Function to generate admin thumbnail URL
721
*/
722
type GetAdminThumbnail = (args: { doc: Record<string, unknown> }) => string;
723
724
/**
725
* File data structure
726
*/
727
interface FileData {
728
/** Original filename */
729
filename: string;
730
/** File size in bytes */
731
filesize: number;
732
/** MIME type */
733
mimeType: string;
734
/** Image width (for images) */
735
width: number;
736
/** Image height (for images) */
737
height: number;
738
/** Generated size variants */
739
sizes: FileSizes;
740
}
741
742
/**
743
* Generated image sizes
744
*/
745
interface FileSizes {
746
[sizeName: string]: FileSize;
747
}
748
749
/**
750
* Individual file size variant
751
*/
752
interface FileSize {
753
/** Generated filename */
754
filename: string;
755
/** File size in bytes */
756
filesize: number;
757
/** MIME type */
758
mimeType: string;
759
/** Size variant name */
760
name: string;
761
/** Image width */
762
width: number;
763
/** Image height */
764
height: number;
765
/** Crop setting used */
766
crop: string;
767
}
768
769
/**
770
* Incoming file during upload
771
*/
772
interface File {
773
/** File buffer data */
774
data: Buffer;
775
/** MIME type */
776
mimetype: string;
777
/** Original filename */
778
name: string;
779
/** File size in bytes */
780
size: number;
781
}
782
```
783
784
**Upload Configuration Examples:**
785
786
```typescript
787
// Basic image upload collection
788
const MediaCollection: CollectionConfig = {
789
slug: "media",
790
upload: {
791
staticURL: "/media",
792
staticDir: "media",
793
disableLocalStorage: false,
794
mimeTypes: ["image/jpeg", "image/png", "image/webp"],
795
imageSizes: [
796
{
797
name: "thumbnail",
798
width: 150,
799
height: 150,
800
fit: "cover",
801
position: "center",
802
},
803
{
804
name: "small",
805
width: 400,
806
height: 300,
807
fit: "cover",
808
},
809
{
810
name: "medium",
811
width: 800,
812
height: 600,
813
fit: "inside",
814
},
815
{
816
name: "large",
817
width: 1600,
818
height: 1200,
819
fit: "inside",
820
},
821
],
822
adminThumbnail: "thumbnail",
823
},
824
fields: [
825
{
826
name: "alt",
827
type: "text",
828
label: "Alt Text",
829
},
830
],
831
};
832
833
// Advanced upload with format conversion
834
const AdvancedMediaCollection: CollectionConfig = {
835
slug: "media",
836
upload: {
837
staticURL: "/media",
838
staticDir: "media",
839
disableLocalStorage: false,
840
mimeTypes: ["image/jpeg", "image/png", "image/webp", "image/avif"],
841
formatOptions: {
842
format: "webp",
843
options: {
844
quality: 80,
845
},
846
},
847
imageSizes: [
848
{
849
name: "thumbnail",
850
width: 150,
851
height: 150,
852
fit: "cover",
853
formatOptions: {
854
format: "webp",
855
options: { quality: 70 },
856
},
857
},
858
{
859
name: "optimized",
860
width: 1200,
861
height: 800,
862
fit: "inside",
863
formatOptions: {
864
format: "avif",
865
options: { quality: 85 },
866
},
867
},
868
],
869
adminThumbnail: ({ doc }) => {
870
return doc.sizes?.thumbnail?.filename || doc.filename;
871
},
872
},
873
fields: [
874
{
875
name: "alt",
876
type: "text",
877
required: true,
878
},
879
{
880
name: "caption",
881
type: "textarea",
882
},
883
],
884
};
885
886
// Cloud storage configuration (S3, etc.)
887
const CloudMediaCollection: CollectionConfig = {
888
slug: "media",
889
upload: {
890
staticURL: "https://cdn.example.com/media",
891
staticDir: "/tmp/uploads", // Temporary local directory
892
disableLocalStorage: true, // Files stored in cloud
893
handlers: [
894
// Custom handlers for cloud upload
895
s3UploadHandler,
896
cloudinaryHandler,
897
],
898
imageSizes: [
899
{
900
name: "thumbnail",
901
width: 200,
902
height: 200,
903
},
904
],
905
},
906
fields: [
907
{
908
name: "cloudinaryId",
909
type: "text",
910
hidden: true,
911
},
912
],
913
};
914
```