# Custom fields

Custom fields extend Strapi’s capabilities by adding new types of 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 documentation is intended to custom fields creators: it describes which APIs and functions developers must use to create a new custom field. The user guide describes how to install and use custom fields from Strapi's admin panel.

Custom fields are a specific type of Strapi plugins that include both a server part and an admin panel part. Both parts should be registered separately before a custom field is usable in Strapi's admin panel.

✏️ NOTE

Once registered, custom fields can be used in models's schema.json.

# Registering a custom field on the server

Strapi's server needs to be aware of all the custom fields to ensure that an attribute using a custom field is valid.

The strapi.customFields object exposes a register() method on the Strapi instance. This method is used to register custom fields on the server during the plugin's server register lifecycle.

strapi.customFields.register() registers one or several custom field(s) on the server by passing an object (or an array of objects) 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

If omitted, the custom field is registered within the global namespace.
String
type The data type the custom field will use String

✏️ NOTE

Currently custom fields can not add new data types to Strapi and should use existing, built-in Strapi data types (e.g. string, number, JSON — see models documentation for the full list).

Example: Registering an example "color" custom field on the server:
// path: ./src/plugins/my-custom-field-plugin/strapi-server.js

module.exports = {
  register({ strapi }) {
    strapi.customFields.register({
      name: 'color',
      plugin: 'color-picker', // the custom 
      type: 'text',
    });
  },
};

# Registering a custom field in the admin panel

Custom fields must be registered in Strapi's admin panel to be available in the Content-type Builder and the Content Manager.

The app.customFields object exposes a register() method on the StrapiApp instance. This method is used to register custom fields in the admin panel during the plugin's admin bootstrap lifecycle.

app.customFields.register() registers one or several custom field(s) in the admin panel by passing an object (or an array of objects) with the following parameters:

Parameter Description Type
name Name of the custom field String
pluginId

(optional)
Name of the plugin creating the custom field

If omitted, the custom field is registered within the global namespace.
String
type Existing Strapi data type the custom field will use String
icon

(optional)
Icon for the custom field React.ComponentType
intlLabel Translation for the name IntlObject (opens new window)
intlDescription Translation for the description IntlObject (opens new window)
components Components needed to display the custom field in the Content Manager (see components)
options

(optional)
Options to be used by the Content-type Builder (see options) Object
Example: Registering an example "color" custom field in the admin panel:
// path: ./src/plugins/color-picker/strapi-server.js

register(app) {
  app.customFields.register({
    name: "color",
    pluginId: "color-picker", // the custom field is created by a color-picker plugin
    type: "text", // the color will be stored as text
    intlLabel: {
      id: "color-picker.color.label",
      defaultMessage: "Color",
    },
    intlDescription: {
      id: "color-picker.color.description",
      defaultMessage: "Select any color",
    } 
    icon: ColorIcon,
    components: {
      Input: async () => import(/* webpackChunkName: "input-component" */ "./Input"),
      View: async () => import(/* webpackChunkName: "view-component" */ "./View"),
    } 
    options: {
      base: [
        /*
          Declare settings to be added to the "Base settings" section
          of the field in the Content-Type Builder
        */ 
        {
          sectionTitle: { // Add a "Format" settings section
            id: 'color-picker.color.section.format',
            defaultMessage: 'Format',
          },
          items: [ // Add settings items to the section
            {
              /*
                Add a "Color format" dropdown
                to choose between 2 different format options
                for the color value: hexadecimal or RGBA
              */
              intlLabel: {
                id: 'color-picker.color.format.label',
                defaultMessage: 'Color format',
              },
              name: 'options.format',
              type: 'select',
              value: 'hex', // option selected by default
              options: [ // List all available "Color format" options
                {
                  key: 'hex',
                  value: 'hex',
                  metadatas: {
                    intlLabel: {
                      id: 'color-picker.color.format.hex',
                      defaultMessage: 'Hexadecimal',
                    },
                  },
                },
                {
                  key: 'rgba',
                  value: 'rgba',
                  metadatas: {
                    intlLabel: {
                      id: 'color-picker.color.format.rgba',
                      defaultMessage: 'RGBA',
                    },
                  },
                },
              ],
            },
          ],
        },
      ],
      advanced: [
        /*
          Declare settings to be added to the "Advanced settings" section
          of the field in the Content-Type Builder
        */ 
      ],
      validator: (args) => ({
        'color-picker': yup.object().shape({
          format: yup.string().oneOf(['hex', 'rgba']),
        }),
      }),
    },
  });
}

✏️ NOTE

Relations, components or dynamic zones can't be used as a custom field's type parameter.

# Components

app.customFields.register() must pass a components object with 1 or 2 of the following components:

Component Description
Input React component to use in the Content Manager's edit view
View Read-only React component to use in the Content Manager's list view
Example: Registering Input and View components imported from dedicated files:
// path: ./src/plugins/my-custom-field-plugin/strapi-server.js

register(app) {
  app.customFields.register({
    // …
    components: {
      Input: async () => import(/* webpackChunkName: "input-component" */ "./Input"),
      View: async () => import(/* webpackChunkName: "view-component" */ "./View"),
    } 
    // …
  });
}

# Options

app.customFields.register() can pass an additional options object with the following parameters:

Options parameter Description Type
base Settings available in the Base settings tab of the field in the Content-type Builder Object or Object[]
advanced Settings available in the Advanced settings tab of the field in the Content-type Builder Object or Object[]
validator Validator function returning an object, used to sanitize input Function

Both base and advanced settings accept an object or an array of objects, each object being a settings section. Each settings section must include:

  • a sectionTitle to declare the title of the section as a React IntlObject
  • and a list of items as an array of objects.

Each object in the items array can contain the following parameters:

Items parameter Description Type
intlLabel Translation for the abel of the setting item IntlObject (opens new window)
name Name of the setting item
Must use the options.setting-name format.
String
type ? String
value ? String
options ? Array of Objects
Example: Declaring settings for an example "color" custom field:
// path: ./src/plugins/my-custom-field-plugin/strapi-server.js

register(app) {
  app.customFields.register({
    // …
    options: {
      base: [
        {
          sectionTitle: {
            id: 'color-picker.color.section.format',
            defaultMessage: 'Format',
          },
          items: [
            {
              intlLabel: {
                id: 'color-picker.color.format.label',
                defaultMessage: 'Color format',
              },
              name: 'options.format',
              type: 'select',
              value: 'hex',
              options: [
                {
                  key: 'hex',
                  value: 'hex',
                  metadatas: {
                    intlLabel: {
                      id: 'color-picker.color.format.hex',
                      defaultMessage: 'Hexadecimal',
                    },
                  },
                },
                {
                  key: 'rgba',
                  value: 'rgba',
                  metadatas: {
                    intlLabel: {
                      id: 'color-picker.color.format.rgba',
                      defaultMessage: 'RGBA',
                    },
                  },
                },
              ],
            },
          ],
        },
      ],
      advanced: [],
      validator: (args) => ({
        'color-picker': yup.object().shape({
          format: yup.string().oneOf(['hex', 'rgba']),
        }),
      }),
    },
  });
}

✏️ NOTE

When extending a custom field’s base and advanced forms in the Content-type Builder, it is not currently possible to import custom input components.