Add configuration for BMad, Claude, OpenCode, and other AI agent tools and workflows.
374 lines
5.6 KiB
Markdown
374 lines
5.6 KiB
Markdown
# Field Types Reference
|
|
|
|
## Core Field Types
|
|
|
|
### Text Fields
|
|
|
|
```ts
|
|
// Basic text
|
|
{ name: 'title', type: 'text', required: true }
|
|
|
|
// With validation
|
|
{
|
|
name: 'email',
|
|
type: 'text',
|
|
validate: (value) => {
|
|
if (!value?.includes('@')) return 'Invalid email'
|
|
return true
|
|
},
|
|
}
|
|
|
|
// With admin config
|
|
{
|
|
name: 'description',
|
|
type: 'textarea',
|
|
admin: {
|
|
placeholder: 'Enter description...',
|
|
description: 'Brief summary',
|
|
},
|
|
}
|
|
```
|
|
|
|
### Slug Field Helper
|
|
|
|
Auto-generate URL-safe slugs:
|
|
|
|
```ts
|
|
import { slugField } from '@payloadcms/plugin-seo'
|
|
|
|
// Or manual implementation
|
|
{
|
|
name: 'slug',
|
|
type: 'text',
|
|
unique: true,
|
|
index: true,
|
|
hooks: {
|
|
beforeValidate: [
|
|
({ data, operation, originalDoc }) => {
|
|
if (operation === 'create' || !originalDoc?.slug) {
|
|
return data?.title?.toLowerCase().replace(/\s+/g, '-')
|
|
}
|
|
return originalDoc.slug
|
|
},
|
|
],
|
|
},
|
|
}
|
|
```
|
|
|
|
### Number Fields
|
|
|
|
```ts
|
|
{ name: 'price', type: 'number', min: 0, required: true }
|
|
{ name: 'quantity', type: 'number', defaultValue: 1 }
|
|
```
|
|
|
|
### Select Fields
|
|
|
|
```ts
|
|
// Simple select
|
|
{
|
|
name: 'status',
|
|
type: 'select',
|
|
options: ['draft', 'published', 'archived'],
|
|
defaultValue: 'draft',
|
|
}
|
|
|
|
// With labels
|
|
{
|
|
name: 'priority',
|
|
type: 'select',
|
|
options: [
|
|
{ label: 'Low', value: 'low' },
|
|
{ label: 'Medium', value: 'medium' },
|
|
{ label: 'High', value: 'high' },
|
|
],
|
|
}
|
|
|
|
// Multi-select
|
|
{
|
|
name: 'categories',
|
|
type: 'select',
|
|
hasMany: true,
|
|
options: ['tech', 'design', 'marketing'],
|
|
}
|
|
```
|
|
|
|
### Checkbox
|
|
|
|
```ts
|
|
{ name: 'featured', type: 'checkbox', defaultValue: false }
|
|
```
|
|
|
|
### Date Fields
|
|
|
|
```ts
|
|
{ name: 'publishedAt', type: 'date' }
|
|
|
|
// With time
|
|
{
|
|
name: 'eventDate',
|
|
type: 'date',
|
|
admin: { date: { pickerAppearance: 'dayAndTime' } },
|
|
}
|
|
```
|
|
|
|
## Relationship Fields
|
|
|
|
### Basic Relationship
|
|
|
|
```ts
|
|
// Single relationship
|
|
{
|
|
name: 'author',
|
|
type: 'relationship',
|
|
relationTo: 'users',
|
|
required: true,
|
|
}
|
|
|
|
// Multiple relationships (hasMany)
|
|
{
|
|
name: 'tags',
|
|
type: 'relationship',
|
|
relationTo: 'tags',
|
|
hasMany: true,
|
|
}
|
|
|
|
// Polymorphic (multiple collections)
|
|
{
|
|
name: 'parent',
|
|
type: 'relationship',
|
|
relationTo: ['pages', 'posts'],
|
|
}
|
|
```
|
|
|
|
### With Filter Options
|
|
|
|
Dynamically filter available options:
|
|
|
|
```ts
|
|
{
|
|
name: 'relatedPosts',
|
|
type: 'relationship',
|
|
relationTo: 'posts',
|
|
hasMany: true,
|
|
filterOptions: ({ data }) => ({
|
|
// Only show published posts, exclude self
|
|
status: { equals: 'published' },
|
|
id: { not_equals: data?.id },
|
|
}),
|
|
}
|
|
```
|
|
|
|
### Join Fields
|
|
|
|
Reverse relationship lookup (virtual field):
|
|
|
|
```ts
|
|
// In Posts collection
|
|
{
|
|
name: 'comments',
|
|
type: 'join',
|
|
collection: 'comments',
|
|
on: 'post', // field name in comments that references posts
|
|
}
|
|
```
|
|
|
|
## Virtual Fields
|
|
|
|
Computed fields that don't store data:
|
|
|
|
```ts
|
|
{
|
|
name: 'fullName',
|
|
type: 'text',
|
|
virtual: true,
|
|
hooks: {
|
|
afterRead: [
|
|
({ data }) => `${data?.firstName} ${data?.lastName}`,
|
|
],
|
|
},
|
|
}
|
|
```
|
|
|
|
## Conditional Fields
|
|
|
|
Show/hide fields based on other values:
|
|
|
|
```ts
|
|
{
|
|
name: 'isExternal',
|
|
type: 'checkbox',
|
|
},
|
|
{
|
|
name: 'externalUrl',
|
|
type: 'text',
|
|
admin: {
|
|
condition: (data) => data?.isExternal === true,
|
|
},
|
|
}
|
|
```
|
|
|
|
## Validation
|
|
|
|
### Custom Validation
|
|
|
|
```ts
|
|
{
|
|
name: 'slug',
|
|
type: 'text',
|
|
validate: (value, { data, operation }) => {
|
|
if (!value) return 'Slug is required'
|
|
if (!/^[a-z0-9-]+$/.test(value)) {
|
|
return 'Slug must be lowercase letters, numbers, and hyphens only'
|
|
}
|
|
return true
|
|
},
|
|
}
|
|
```
|
|
|
|
### Async Validation
|
|
|
|
```ts
|
|
{
|
|
name: 'username',
|
|
type: 'text',
|
|
validate: async (value, { payload }) => {
|
|
if (!value) return true
|
|
const existing = await payload.find({
|
|
collection: 'users',
|
|
where: { username: { equals: value } },
|
|
})
|
|
if (existing.docs.length > 0) return 'Username already taken'
|
|
return true
|
|
},
|
|
}
|
|
```
|
|
|
|
## Group Fields
|
|
|
|
Organize related fields:
|
|
|
|
```ts
|
|
{
|
|
name: 'meta',
|
|
type: 'group',
|
|
fields: [
|
|
{ name: 'title', type: 'text' },
|
|
{ name: 'description', type: 'textarea' },
|
|
],
|
|
}
|
|
```
|
|
|
|
## Array Fields
|
|
|
|
Repeatable sets of fields:
|
|
|
|
```ts
|
|
{
|
|
name: 'socialLinks',
|
|
type: 'array',
|
|
fields: [
|
|
{ name: 'platform', type: 'select', options: ['twitter', 'linkedin', 'github'] },
|
|
{ name: 'url', type: 'text' },
|
|
],
|
|
}
|
|
```
|
|
|
|
## Blocks (Polymorphic Content)
|
|
|
|
Different content types in same array:
|
|
|
|
```ts
|
|
{
|
|
name: 'layout',
|
|
type: 'blocks',
|
|
blocks: [
|
|
{
|
|
slug: 'hero',
|
|
fields: [
|
|
{ name: 'heading', type: 'text' },
|
|
{ name: 'image', type: 'upload', relationTo: 'media' },
|
|
],
|
|
},
|
|
{
|
|
slug: 'content',
|
|
fields: [
|
|
{ name: 'richText', type: 'richText' },
|
|
],
|
|
},
|
|
],
|
|
}
|
|
```
|
|
|
|
## Point (Geolocation)
|
|
|
|
```ts
|
|
{
|
|
name: 'location',
|
|
type: 'point',
|
|
label: 'Location',
|
|
}
|
|
|
|
// Query nearby
|
|
await payload.find({
|
|
collection: 'stores',
|
|
where: {
|
|
location: {
|
|
near: [-73.935242, 40.730610, 5000], // lng, lat, maxDistance (meters)
|
|
},
|
|
},
|
|
})
|
|
```
|
|
|
|
## Upload Fields
|
|
|
|
```ts
|
|
{
|
|
name: 'featuredImage',
|
|
type: 'upload',
|
|
relationTo: 'media',
|
|
required: true,
|
|
}
|
|
```
|
|
|
|
## Rich Text
|
|
|
|
```ts
|
|
{
|
|
name: 'content',
|
|
type: 'richText',
|
|
// Lexical editor features configured in payload.config.ts
|
|
}
|
|
```
|
|
|
|
## UI Fields (Presentational)
|
|
|
|
Fields that don't save data:
|
|
|
|
```ts
|
|
// Row layout
|
|
{
|
|
type: 'row',
|
|
fields: [
|
|
{ name: 'firstName', type: 'text', admin: { width: '50%' } },
|
|
{ name: 'lastName', type: 'text', admin: { width: '50%' } },
|
|
],
|
|
}
|
|
|
|
// Tabs
|
|
{
|
|
type: 'tabs',
|
|
tabs: [
|
|
{ label: 'Content', fields: [...] },
|
|
{ label: 'Meta', fields: [...] },
|
|
],
|
|
}
|
|
|
|
// Collapsible
|
|
{
|
|
type: 'collapsible',
|
|
label: 'Advanced Options',
|
|
fields: [...],
|
|
}
|
|
```
|