
Webiny API Cms Custom Field Type
How to implement a custom CMS field type that integrates with the model builder's...
Install
npx skills add webiny/webiny-js --skill webiny-api-cms-custom-field-type -g -a claude-code -y- Repository
- webiny/webiny-js8.1k
- Category
- Engineering
- Updated
- 5d ago
- License
- See repository
- Context cost
- Mediumabout 2,850 tokens
- Runs scripts
- No, instructions only
What it does
How to implement a custom CMS field type that integrates with the model builder's fluent API. Covers extending DataFieldBuilder, composing validator interfaces, creating a FieldTypeFactory, registering via DI, and module augmentation for TypeScript autocomplete on the fields() registry.
Custom CMS Field Type
TL;DR
A custom field type is a class that extends DataFieldBuilder<"yourType">, paired with a factory class implementing FieldType.Factory. Register the factory with container.register(YourFieldType). Add a module augmentation on "webiny/api/cms/model" so the fields registry method gets TypeScript autocomplete.
When to Use This
Use a custom field type when:
- You need a field with a storage format or validation logic not covered by the built-in types (
text,number,boolean,datetime,file,ref,object,richText,longText,json,dynamicZone) - You want to expose a fluent builder API (e.g.,
fields.slug(),fields.color()) inModelFactoryimplementations
Field Type Structure
A custom field type consists of three parts:
- Builder interface, extends
DataFieldBuilder<"type">plusFieldTypeValidator.*types - Builder class, implements the interface, calls
this.validation()for each validator - Factory class, implements
FieldType.Factory, creates builder instances
As a standalone extension (not part of a larger feature), the directory layout is:
extensions/
└── SlugFieldType/
├── SlugFieldType.ts # builder interface, builder class, factory class
└── feature.ts # createFeature, registers the factory into the DI container
feature.ts:
// extensions/SlugFieldType/feature.ts
import { createFeature } from "webiny/api";
import { SlugFieldType } from "./SlugFieldType.js";
export const SlugFieldTypeFeature = createFeature({
name: "SlugFieldType",
register(container) {
container.register(SlugFieldType);
}
});
Register in the API entry point:
// api/Extension.ts
import { createFeature } from "webiny/api";
import { SlugFieldTypeFeature } from "~/extensions/SlugFieldType/feature.js";
