381 lines
11 KiB
Markdown
381 lines
11 KiB
Markdown
---
|
|
tags: [payloadcms, tech-patterns]
|
|
topic: payloadcms
|
|
sources:
|
|
- https://payloadcms.com/docs/fields/overview
|
|
- https://payloadcms.com/docs/fields/text
|
|
- https://payloadcms.com/docs/fields/textarea
|
|
- https://payloadcms.com/docs/fields/number
|
|
- https://payloadcms.com/docs/fields/email
|
|
- https://payloadcms.com/docs/fields/date
|
|
- https://payloadcms.com/docs/fields/checkbox
|
|
- https://payloadcms.com/docs/fields/code
|
|
- https://payloadcms.com/docs/fields/json
|
|
- https://payloadcms.com/docs/fields/point
|
|
- https://payloadcms.com/docs/fields/radio
|
|
- https://payloadcms.com/docs/fields/select
|
|
- https://payloadcms.com/docs/fields/ui
|
|
created: 2026-05-15
|
|
---
|
|
|
|
# PayloadCMS — Fields: Basic
|
|
|
|
## Overview
|
|
|
|
Scalar (basic) fields store a single value per document. They map directly to database columns and drive typed inputs in the Admin Panel. All fields live inside the `fields` array of a [[wiki/payloadcms/configuration|Configuration]] (Collection or Global).
|
|
|
|
See [[wiki/payloadcms/fields-complex|Fields: Complex]] for structural/relational fields.
|
|
|
|
## Field Types Quick Reference
|
|
|
|
| Field | Type string | Key options |
|
|
|-------|-------------|-------------|
|
|
| Text | `text` | `minLength`, `maxLength`, `hasMany`, `unique` |
|
|
| Textarea | `textarea` | `minLength`, `maxLength`, `admin.rows` |
|
|
| Number | `number` | `min`, `max`, `hasMany`, `admin.step` |
|
|
| Email | `email` | `unique`, `index` |
|
|
| Date | `date` | `timezone`, `admin.date.pickerAppearance` |
|
|
| Checkbox | `checkbox` | `defaultValue` (boolean) |
|
|
| Code | `code` | `admin.language`, `admin.editorOptions` |
|
|
| JSON | `json` | `jsonSchema` (local or remote) |
|
|
| Point | `point` | index defaults to `2dsphere`, not supported in SQLite |
|
|
| Radio | `radio` | `options` (required), `admin.layout` |
|
|
| Select | `select` | `options`, `hasMany`, `filterOptions`, `enumName` |
|
|
| UI | `ui` | `admin.components.Field` (required), presentational only |
|
|
|
|
## Common Field Options
|
|
|
|
These options are shared by almost all data-storing fields:
|
|
|
|
| Option | Type | Description |
|
|
|--------|------|-------------|
|
|
| `name` * | `string` | Property name in DB and API. Required for data fields. |
|
|
| `label` | `string \| Record<string,string>` | Admin Panel label, auto-generated from `name` if omitted. |
|
|
| `required` | `boolean` | Prevents saving without a value. |
|
|
| `defaultValue` | any | Initial value; can be a static value or async function. |
|
|
| `unique` | `boolean` | DB-level unique index across the collection. |
|
|
| `index` | `boolean` | Creates a DB index for faster queries. |
|
|
| `localized` | `boolean` | Stores a per-locale copy. Requires localization enabled globally. |
|
|
| `hidden` | `boolean` | Hides from all APIs and Admin; still saved to DB. |
|
|
| `validate` | `function` | Custom validation, runs on both client and server. |
|
|
| `hooks` | `object` | `beforeValidate`, `beforeChange`, `afterChange`, `afterRead`. |
|
|
| `access` | `object` | Field-level read/create/update access control functions. |
|
|
| `saveToJWT` | `boolean` | Include value in user JWT (auth collections only, top-level fields). |
|
|
| `virtual` | `boolean \| string` | `true` = not persisted to DB; string path = virtual relationship link. |
|
|
| `custom` | `object` | Arbitrary extension data for plugins. |
|
|
| `typescriptSchema` | `JSONSchema` | Override generated TypeScript type with a JSON schema. |
|
|
|
|
Admin-level sub-options available on all fields (via `admin: {}`):
|
|
|
|
| Option | Description |
|
|
|--------|-------------|
|
|
| `description` | Help text rendered below the field. |
|
|
| `condition` | `(data, siblingData) => boolean` — conditional rendering. |
|
|
| `readOnly` | Renders as read-only in Admin. |
|
|
| `disabled` | Disables the field UI (granular: `{ field?, column?, filter?, ... }`). |
|
|
| `position` | `'sidebar'` to move field to the document sidebar. |
|
|
| `width` | CSS width for use inside `row` fields (e.g. `'50%'`). |
|
|
| `components` | Override `Field`, `Label`, `Cell` React components. |
|
|
|
|
---
|
|
|
|
## Each Field
|
|
|
|
### Text
|
|
|
|
Stores a `string`. Most commonly used field.
|
|
|
|
```ts
|
|
import type { Field } from 'payload'
|
|
|
|
const titleField: Field = {
|
|
name: 'pageTitle',
|
|
type: 'text',
|
|
required: true,
|
|
minLength: 3,
|
|
maxLength: 120,
|
|
admin: {
|
|
placeholder: 'Enter page title...',
|
|
autoComplete: 'off',
|
|
rtl: false,
|
|
},
|
|
}
|
|
```
|
|
|
|
**Extra options:** `minLength`, `maxLength`, `hasMany` (array of strings), `minRows`, `maxRows` (when `hasMany`), `admin.placeholder`, `admin.autoComplete`, `admin.rtl`.
|
|
|
|
**Slug Field shortcut:** `import { slugField } from 'payload'` — auto-generates URL slug from another field with a lock/unlock UI.
|
|
|
|
**Gotcha:** `unique: true` creates a collection-wide DB index, not per-document uniqueness.
|
|
|
|
---
|
|
|
|
### Textarea
|
|
|
|
Nearly identical to Text but renders a taller input — use for descriptions, bios, meta.
|
|
|
|
```ts
|
|
const descField: Field = {
|
|
name: 'metaDescription',
|
|
type: 'textarea',
|
|
maxLength: 160,
|
|
admin: {
|
|
rows: 3,
|
|
placeholder: 'Short summary...',
|
|
},
|
|
}
|
|
```
|
|
|
|
**Extra options:** same as Text plus `admin.rows` (default `2`).
|
|
|
|
---
|
|
|
|
### Number
|
|
|
|
Stores a numeric value.
|
|
|
|
```ts
|
|
const priceField: Field = {
|
|
name: 'price',
|
|
type: 'number',
|
|
min: 0,
|
|
required: true,
|
|
admin: {
|
|
step: 0.01,
|
|
placeholder: '0.00',
|
|
},
|
|
}
|
|
```
|
|
|
|
**Extra options:** `min`, `max`, `hasMany`, `minRows`, `maxRows`, `admin.step`, `admin.placeholder`, `admin.autoComplete`.
|
|
|
|
---
|
|
|
|
### Email
|
|
|
|
Like Text but validates that the value is a valid email address.
|
|
|
|
```ts
|
|
const emailField: Field = {
|
|
name: 'contactEmail',
|
|
type: 'email',
|
|
required: true,
|
|
unique: true,
|
|
admin: {
|
|
placeholder: 'user@example.com',
|
|
},
|
|
}
|
|
```
|
|
|
|
No unique-to-email options beyond standard text options. Format validation is automatic.
|
|
|
|
---
|
|
|
|
### Date
|
|
|
|
Stores a full ISO datetime string (`YYYY-MM-DDTHH:mm:ss.SSSZ`). UI uses `react-datepicker`.
|
|
|
|
```ts
|
|
const publishedAtField: Field = {
|
|
name: 'publishedAt',
|
|
type: 'date',
|
|
required: true,
|
|
admin: {
|
|
date: {
|
|
pickerAppearance: 'dayAndTime', // dayAndTime | dayOnly | timeOnly | monthOnly
|
|
displayFormat: 'd MMM yyyy HH:mm',
|
|
timeIntervals: 15,
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
**Timezone support:**
|
|
|
|
```ts
|
|
{
|
|
name: 'eventTime',
|
|
type: 'date',
|
|
timezone: {
|
|
defaultTimezone: 'America/New_York',
|
|
supportedTimezones: [
|
|
{ label: 'New York', value: 'America/New_York' },
|
|
{ label: 'London', value: 'Europe/London' },
|
|
],
|
|
},
|
|
}
|
|
```
|
|
|
|
Timezone value is saved in a companion column `<fieldName>_tz`. Date is always stored in UTC — handle conversion in your frontend.
|
|
|
|
**`displayFormat`** only affects the cell display; the stored value is always full ISO.
|
|
|
|
---
|
|
|
|
### Checkbox
|
|
|
|
Stores a `boolean`.
|
|
|
|
```ts
|
|
const featuredField: Field = {
|
|
name: 'isFeatured',
|
|
type: 'checkbox',
|
|
defaultValue: false,
|
|
}
|
|
```
|
|
|
|
**Gotcha:** When `required: true`, `defaultValue` must be `true` — otherwise required validation will always fail on `false`.
|
|
|
|
---
|
|
|
|
### Code
|
|
|
|
Stores a `string` but renders a Monaco-editor code block in Admin.
|
|
|
|
```ts
|
|
const snippetField: Field = {
|
|
name: 'trackingCode',
|
|
type: 'code',
|
|
admin: {
|
|
language: 'javascript', // any Monaco language slug
|
|
editorOptions: { lineNumbers: 'off' },
|
|
},
|
|
}
|
|
```
|
|
|
|
**Gotcha:** Saves as raw string to DB — not parsed. Different from JSON field.
|
|
|
|
---
|
|
|
|
### JSON
|
|
|
|
Stores raw JSON (parsed object/array) in the DB. Also Monaco-editor UI.
|
|
|
|
```ts
|
|
const configField: Field = {
|
|
name: 'settings',
|
|
type: 'json',
|
|
jsonSchema: {
|
|
uri: 'a://schema/settings.json', // required — must be unique URI
|
|
fileMatch: ['a://schema/settings.json'], // required
|
|
schema: {
|
|
type: 'object',
|
|
properties: {
|
|
theme: { enum: ['light', 'dark'] },
|
|
},
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
`jsonSchema` enables typeahead in Admin and validates on save. Can also point to a remote URL — Payload fetches the schema.
|
|
|
|
**Gotcha:** Code field stores string; JSON field stores a parsed value — do not confuse them.
|
|
|
|
---
|
|
|
|
### Point
|
|
|
|
Stores GeoJSON `[longitude, latitude]` coordinates with an automatic `2dsphere` index.
|
|
|
|
```ts
|
|
const locationField: Field = {
|
|
name: 'location',
|
|
type: 'point',
|
|
}
|
|
```
|
|
|
|
Supports geospatial query operators: `near`, `within` (polygon), `intersects` (polygon).
|
|
|
|
**Gotcha:** Not supported in SQLite. Disabling the index (`index: false`) removes geospatial query support.
|
|
|
|
---
|
|
|
|
### Radio
|
|
|
|
Single-select from a predefined list. Renders a radio group.
|
|
|
|
```ts
|
|
const statusField: Field = {
|
|
name: 'status',
|
|
type: 'radio',
|
|
options: [
|
|
{ label: 'Draft', value: 'draft' },
|
|
{ label: 'Published', value: 'published' },
|
|
{ label: 'Archived', value: 'archived' },
|
|
],
|
|
defaultValue: 'draft',
|
|
admin: {
|
|
layout: 'horizontal', // horizontal | vertical
|
|
},
|
|
}
|
|
```
|
|
|
|
**Gotcha:** Option `value` strings must not contain hyphens — GraphQL enum constraint. Underscores are fine.
|
|
|
|
---
|
|
|
|
### Select
|
|
|
|
Dropdown single or multi-select from a predefined list.
|
|
|
|
```ts
|
|
const tagsField: Field = {
|
|
name: 'tags',
|
|
type: 'select',
|
|
hasMany: true,
|
|
options: [
|
|
{ label: 'News', value: 'news' },
|
|
{ label: 'Tutorial', value: 'tutorial' },
|
|
{ label: 'Release', value: 'release' },
|
|
],
|
|
admin: {
|
|
isClearable: true,
|
|
isSortable: true, // drag-and-drop reorder, only when hasMany
|
|
},
|
|
}
|
|
```
|
|
|
|
**`filterOptions`** — function receiving `{ options, data, siblingData, ... }` that returns a filtered options array (different from relationship `filterOptions` which returns a Where query).
|
|
|
|
**Extra options:** `enumName` (custom Postgres enum name), `dbName` (custom join table name when `hasMany`), `interfaceName`.
|
|
|
|
---
|
|
|
|
### UI
|
|
|
|
Presentational-only. No data stored. Renders a custom React component anywhere in the field schema.
|
|
|
|
```ts
|
|
const helpTextField: Field = {
|
|
name: 'myHelper',
|
|
type: 'ui',
|
|
admin: {
|
|
components: {
|
|
Field: '/path/to/MyHelpText', // required
|
|
Cell: '/path/to/MyHelpCell', // optional — list view column
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
Use cases: custom buttons (Refund, Clear Cache, View Page), contextual help text, action components.
|
|
|
|
**Gotcha:** `admin.components.Field` is required — without it nothing renders. Does not participate in validation or hooks.
|
|
|
|
---
|
|
|
|
## Gotchas
|
|
|
|
- **`unique: true` on nested fields** (inside Array/Group) creates a collection-wide index, not per-row uniqueness. Use a custom `validate` for per-row enforcement.
|
|
- **`hidden: true`** still persists data to DB — use field `access` to truly restrict reads.
|
|
- **`localized: true`** requires global localization config (`i18n`) to be enabled first.
|
|
- **`virtual: true`** prevents DB storage entirely; useful for computed/derived fields.
|
|
- **Radio/Select values** must not contain hyphens — GraphQL enum naming constraint.
|
|
- **Point field** is unsupported in SQLite databases.
|
|
- **Date timezone** column is auto-named `<fieldName>_tz`; date itself stored in UTC.
|
|
|
|
## Related
|
|
|
|
- [[wiki/payloadcms/fields-complex|Fields: Complex]]
|
|
- [[wiki/payloadcms/configuration|Configuration]]
|