# Custom fields
Custom fields are plugins that extend Strapi’s capabilities by adding new fields to content-types. Once created or installed, custom fields can be used in the Content-Types Builder and Content Manager just like built-in fields.
The present reference documentation is intended to custom fields creators. It describes how custom fields work and can be created from a developer point of view, describing the APIs available to build a new custom field. The user guide describes how to install and use custom fields from Strapi's admin panel.
🤓 Prefer to learn by building?
If you'd rather directly jump to a concrete example, see the Creating a color custom field guide page for step-by-step instructions on how to build your first custom field from scratch.
Custom fields are a specific type of Strapi plugins that include both a back-end (or server) part and a front-end (or admin panel) part. Both parts should be registered for the custom fields to be available and usable in Strapi's admin panel:
strapi.customFields.registerregisters the server part of a custom field instrapi-server.jsapp.customFields.registerregisters the admin panel part of a custom field instrapi-admin.js
Once registered, custom fields can be used in models's schema.json. Custom fields' attributes should declare their type as customField and use the customField property to mention the registered custom field to use (see model's custom fields documentation).
# Registering a custom field on the server
On the server part, Strapi needs to be aware of all custom fields to ensure that an attribute using a custom field is valid. To achieve this, the strapi.customFields object exposes a register() method on the Strapi instance.
strapi.customFields.register() registers a custom field on the server during the plugin's server register lifecycle and should pass an object with the following parameters:
| Parameter | Description | Type |
|---|---|---|
name | The name of the custom field | String |
plugin(optional) | The name of the plugin creating the custom fields | String |
type | The existing, built-in Strapi data type the custom field will use (e.g. string, number, JSON — see models documentation for the full list). | String |
TypeScript shapes to register a custom field on the server:
The following Strapi API is exposed to help you register a custom field on the server:
interface CustomFieldServerOptions {
// The name of the custom field
name: string;
// The name of the plugin creating the custom field
plugin?: string;
// The existing Strapi data type the custom field will use
type: string;
}
strapi.customFields.register(
options: CustomFieldServerOptions | CustomFieldServerOptions[]
);
Example: Registering an example "checkbox" custom field on the server:
// path: ./src/plugins/my-custom-field-plugin/strapi-server.js
module.exports = {
register({ strapi }) {
strapi.customFields.register({
name: 'checkbox',
plugin: 'my-custom-field-plugin',
type: 'boolean',
});
},
};
# Registering a custom field in the admin panel
On the admin panel part, the custom field should be described to be available in the Content-Type Builder and the Content Manager. To achieve this, the app.customFields exposes a register method on the StrapiApp instance.
app.customFields.register() registers a custom field in the admin panel during the plugin's admin bootstrap lifecycle and should pass an object (or an array of objects) with the following parameters:
| Parameter | Description | Type |
|---|---|---|
name | The name of the custom field | String |
pluginId(optional) | The name of the plugin creating the custom field | String |
type | The existing Strapi data type the custom field will use | String |
intlLabel | The translation for the name | IntlObject |
intlDescription | The translation for the description | IntlObject |
icon(optional) | The icon for the custom field | React.ComponentType |
components | The components needed to display the custom field in the Content Manager (see components) | |
options(optional) | The settings to extend in the Content-Type Builder (see options) | Object |
✏️ NOTE
Relations, components or dynamic zones can't be used as a custom field's type parameter.
TypeScript shapes to register a custom field in the admin panel:
The following Strapi APIs are exposed to help you register a custom field on the server:
// You can also pass an array of objects to register several custom fields at once
app.customFields.register(
options: CustomFieldAdminOptions | CustomFieldAdminOptions[]
);
interface CustomFieldAdminOptions {
// The name of the custom field
name: string;
// The name of the plugin creating the custom field
pluginId?: string;
// The existing Strapi data type the custom field will use
type: string;
// The translation for the name
intlLabel: IntlObject;
// The translation for the description
intlDescription: IntlObject;
// The icon for the custom field
icon?: React.ComponentType;
// The components needed to display the custom field in the Content Manager
components: {
// Input component for the Edit view
Input: () => Promise<{ default: React.ReactComponent }>;
// Read only component for the List view
View: () => Promise<{ default: React.ReactComponent }>;
};
// The settings to extend in the Content-Type Builder
options?: {
base: CTBFormSection[];
advanced: CTBFormSection[];
validator: (args) => object;
}
}
interface IntlObject {
id: string;
defaultMessage: string;
}
interface CTBFormSection {
sectionTitle: IntlObject;
items: CTBFormInput[];
}
interface CTBFormInput {
name: string;
description: InltObject;
type: string;
intlLabel: IntlObject;
}
Example: Registering an example "checkbox" custom field in the admin panel:
// strapi-admin.js
register(app) {
app.customFields.register({
name: "checkbox",
pluginId: "checkbox",
type: "boolean",
intlLabel: {
id: "checkbox.label",
defaultMessage: "Checked",
},
intlDescription: {
id: "checkbox.description",
defaultMessage: "Click to toggle the checkbox",
}
icon: CheckboxIcon,
components: {
Input: async () => import(/* webpackChunkName: "input-component" */ "./Input"),
View: async () => import(/* webpackChunkName: "view-component" */ "./View"),
},
});
}
# Components
The components parameter used in app.customFields.register() should include 2 components:
- an
Inputcomponent to define the React component to use in the Content Manager's edit view, - and a
Viewcomponent View to define a read-only component used in the Content Manager's list view.
Both components could be declared as promises returning a React component imported from another file (e.g. Input: async () => import(/* webpackChunkName: "input-component" */ "./Input").
# Options
app.customFields.register() can pass additional options to be used for the base and advanced settings tabs of the Content-Type Builder. The options object accepts the following parameters:
| Options parameter | Description | Type |
|---|---|---|
base | Settings available in the Base settings tab of the Content-Type Builder | Object or Object[] |
advanced | Settings available in the Advanced settings tab of the Content-Type Builder | Object or Object[] |
validator | Validator function returning an object (useful to sanitize input, for instance) | Function |
Both base and advanced settings accept:
- a
sectionTitle(as an ReactIntlObject) - and a list of
itemsas an array of objects, each object containing the following parameters:
| Items parameter | Description | Type |
|---|---|---|
intlLabel | Label for the setting item, in the React Intl format | Object |
name | Name of the setting to be used, in the following format: options.<setting-name> | String |
type | ? | String |
value | ? | String |
metadatas | ? | Object |
✏️ NOTE
When extending a custom field’s base and advanced forms in the Content-type Builder, it is not yet possible to import custom input components.
TypeScript shapes to declare options:
The following types and shapes are used to describe the options when registering a custom field in the admin panel:
options?: {
base: CTBFormSection[];
advanced: CTBFormSection[];
validator: (args) => object;
}
interface IntlObject {
id: string;
defaultMessage: string;
}
interface CTBFormSection {
sectionTitle: IntlObject;
items: CTBFormInput[];
}
interface CTBFormInput {
name: string;
description: InltObject;
type: string;
intlLabel: IntlObject;
}
Example of options passed when registering a custom field in the admin panel:
(TODO)