or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

authentication.mdconfiguration.mdcore-operations.mdfield-types.mdglobal-operations.mdindex.mdpreferences.mdversion-control.md

field-types.mddocs/

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

```