Fields
Fields are the inputs of a section's form and the columns of its table. nextjs-cms ships 17 field types.
Every field is created with a helper function from nextjs-cms/core/fields:
import { textField } from 'nextjs-cms/core/fields'
const title = textField({ name: 'title', required: true })The helper validates its options immediately (a typo like maxLenght throws when the section file loads, naming the field) and returns a plain config object you pass to a section's fields.
All field types
| Helper | Input | MySQL column | Page |
|---|---|---|---|
textField | Single-line text | VARCHAR(maxLength ?? 255) | textField |
textAreaField | Multi-line text | LONGTEXT | textAreaField |
richTextField | WYSIWYG editor (HTML) | LONGTEXT | richTextField |
slugField | URL slug, generated from a text field | VARCHAR(255) | slugField |
passwordField | Password, stored bcrypt-hashed | VARCHAR(255) | passwordField |
numberField | Number (int, float, double, bigint, auto-increment) | TINYINT … BIGINT, FLOAT, DOUBLE | numberField |
checkboxField | Switch | BOOLEAN | checkboxField |
colorField | Color picker | CHAR(7) | colorField |
dateField | Date, date-time, or timestamp picker | DATE, DATETIME, TIMESTAMP | dateField |
dateRangeField | Start and end date | two DATE/DATETIME columns | dateRangeField |
selectField | Dropdown (static, DB, or section options) | ENUM, INT, or VARCHAR(255) | selectField |
selectMultipleField | Multi-select | VARCHAR(255) or a join table | selectMultipleField |
tagsField | Free-form tags | LONGTEXT or a join table | tagsField |
mapField | Google Maps location picker | VARCHAR(200) | mapField |
photoField | Image upload, resized with sharp | VARCHAR(50) (file name) | photoField |
videoField | Video upload | VARCHAR(50) (file name) | videoField |
documentField | PDF, Office, text, CSV upload | VARCHAR(50) (file name) | documentField |
Columns are NOT NULL when the field is required (and not conditional), otherwise nullable. Text columns use utf8mb4 with utf8mb4_unicode_ci.
Options every field accepts
| Option | Type | Default | Description |
|---|---|---|---|
name | string | required | Column name and form key. Unique within the section. |
label | string | Record<locale, string> | from name | Form label. 'published_at' becomes "Published At" when omitted. |
required | boolean | false | Reject empty values; make the column NOT NULL. |
defaultValue | depends on the field | none | Initial value of the form and the column's DEFAULT. |
order | number | none | Sort position within the form or group. |
conditionalRules | rule array or and() / or() | none | Show (and save) the field only when rules match. |
adminGenerated | true | false | 'readonly' | true | Whether editors fill the field in. |
localized | boolean | false | Store a translation per locale. |
Each is explained with examples in Common Field Options.
Reusing a field across options
A field config is a value. Declare it once and reference it wherever a section option needs a field:
const title = textField({ name: 'title', required: true })
const slug = slugField({ name: 'slug', for: title }) // slug source
const cover = photoField({ name: 'cover' })
export default hasItemsSection({
headingField: title, // list title
coverPhotoField: cover, // list thumbnail
search: { searchFields: [title] }, // search box
db: { table: 'posts', unique: [{ columns: [slug] }] }, // constraint
fields: [title, slug, cover],
// ...
})How a field is saved
On every create or update, each field goes through the same steps:
- Visibility: if the field has
conditionalRulesand they don't match the submitted values, the field is skipped entirely (not validated, not saved). - Required check:
requiredfields must have a non-empty value. - Preparation: type-specific validation and transformation. Length and range checks, slug normalization, password hashing, image decoding and resizing, rich-text sanitizing.
- Uniqueness:
db.uniqueconstraints are checked against the table. - Write: the column values are inserted or updated.
- Post-submit: files are written to disk, join tables (
destinationDb) are rewritten, inline editor images are saved. If this step fails, the write is rolled back.