Sitemap

How to Create a Custom Admin UI Field Component in Strapi

6 min readSep 5, 2022

I’ve been working with the Headless CMS Strapi for a couple of months on a few little projects. It’s extremely fast, quick, and seamless to create a Content Management System (CMS) with an API, with plenty of other features.

Out of the box, Strapi provides the most collection fields you will ever need. 99% of the collection types you create will use the fields Strapi provides. Eventually, you will need that one field component in the Admin UI to cater for a specific need.

Press enter or click to view image in full size
Screenshot of the Strapi Content Management System’s Admin UI
Screenshot of the Strapi Content Management System’s Admin UI

In this article, I want to show how I’ve created a Strapi Admin Field Component I can use in my own Collection Types. This component is really simple, it will show an image using the URL provided by the text field when a value exists.

Pre-requisites

Before we begin, it’s assumed you have an existing Strapi installation up and running. If not, run the following command in Terminal and follow instructions to set up your Strapi on your system.

npx create-strapi-app@latest your-project-name

Additionally, you cannot set up a new plugin in Strapi without completing the installation. If you haven’t already, run yarn develop --watch-adminor npm run develop --watch-admin and navigate to http://localhost:8000 in your favourite browser to complete the setup.

1 Create the plugin

With your local Strapi project up and running, it’s time we create the plugin that will create an Admin UI Field Component in the Content Manager forms. The easiest way to create a new plugin is to use the Strapi CLI commands, you can execute this using strapi generate or yarn strapi generate. This will show the following options:

% yarn strapi generate        
yarn run v1.22.19
$ strapi generate
? Strapi Generators
api - Generate a basic API
controller - Generate a controller for an API
content-type - Generate a content type for an API
❯ plugin - Generate a basic plugin
policy - Generate a policy for an API
middleware - Generate a middleware for an API
service - Generate a service for an API

Using your keyboard’s up and down arrows, move the greater-than symbol (>) down to the plugin and hit Enter/Return. The next option will request a name, fulfill this with the name of your new field. In my example, I’m going to refer to this field as url-image:

? Plugin name url-image

Next, choose your preferred language. In my example, I’m going to use TypeScript. Use your keyboard’s up and down arrows to move the greater-than symbol down to TypeScript and hit Enter/Return.

? Choose your preferred language 
JavaScript
❯ TypeScript

2 Build the plugin

Your plugin is now generated in the /src/plugins folder with the basic setup but it’s not ready to be used. Like many other systems, a plugin in Strapi is like its own project and has its own ecosystem.

Navigate to the plugin directory and install its dependencies:

yarn

or

npm install

Next, build the plugin:

yarn build

or

npm run build

3 Initiate the Plugin

Now the plugin is ready to go, create a /config/plugins.ts file if your project doesn’t already have one, and insert the following code:

export default {
'url-image': {
enabled: true,
resolve: './src/plugins/url-image'
}
}

If you’re using a different name, be sure to substitute “url-image” for the name of your plugin.

With the new plugin activated, stop any existing servers from running and run yarn develop --watch-admin in the root directory of the project. Within the Strapi Admin UI, you should now see the home page for the new plugin in the left menu:

Press enter or click to view image in full size
Strapi Admin UI Showing the Homepage of the New Plugin

4 Create the Custom Field Component

Now we get to create our custom field component, go to the plugin admin’s components directory /src/plugins/url-image/admin/src/components and create a new folder for your component. In my example, I’m going to create a UrlImage directory.

mkdir src/plugins/url-image/admin/src/components/UrlImage

In the new directory, create an index.tsx (TypeScript) or index.js (JavaScript) file.

Within this file, create your new component. As mentioned earlier, my component is going to be very simple, it will show an image in the form of the Collection Type using the value in the text field as the source (src).

import React from 'react';
import { useIntl } from 'react-intl';
import { Box, Stack, TextInput } from '@strapi/design-system';
const UrlImage = ({
description,
disabled,
error,
intlLabel,
name,
onChange,
placeholder,
required,
value
}) => {
const { formatMessage } = useIntl();
return (
<Stack spacing={1}>
<TextInput
disabled={disabled}
error={error}
hint={description ? formatMessage(description) : ''}
label={intlLabel ? formatMessage(intlLabel) : ''}
name={name}
onChange={(event) => {onChange({target: {name, value: event.target.value, type: 'string' }})}}
placeholder={placeholder ? formatMessage(placeholder) : ''}
required={required}
value={value || ''}
/>
<Box padding={1}>
{value &&
<img src={`${value}`} style={{maxWidth: '100%'}} />
}
</Box>
</Stack>
);
};
export default UrlImage;

5 Add the field to the app

In our new plugin’s admin directory’s index.tsx file src/plugins/url-image/admin/src, we need to import our new component at the top:

import UrlImage from './components/UrlImage';

Then add the field within the register function:

register(app) {
...
app.addFields({
Component: UrlImage,
type: pluginId
});
...
},

6 Mutate the Edit View Hook

With the field added to the application, we can now mutate the Edit View hook to show our new component when desired. In our new plugin’s admin directory, create a mutateEditViewHook.ts (TypeScript) or mutateEditViewHook.js (JavaScript) file with the following:

import pluginId from './pluginId';/**
* Checks if the field in the layout's row has the url-image enabled.
* @param {array} layouts - The layouts in the current content-type
* @returns {array} - The updated layouts
*/
const mutateLayouts = (layouts) => {
return layouts.map((row) => {
const mutatedRow = row.reduce((acc, field) => {
const hasMapFieldEnabled = field.fieldSchema.pluginOptions?.[pluginId].enabled;
if (!hasMapFieldEnabled) {
return [...acc, field];
}
return [...acc, {
...field,
fieldSchema: {
...field.fieldSchema,
type: pluginId
}
}]
}, []);
return mutatedRow;
});
};
/**
* Behaviours triggered by the 'Admin/CM/pages/EditView/mutate-edit-view-layout' hook.
*/
const mutateEditViewHook = ({layout, query}) => {
const mutateEditLayout = mutateLayouts(layout.contentType.layouts.edit);
const modifiedLayouts = {
...layout.contentType.layouts,
edit: mutateEditLayout,
};
return {
layout: {
...layout,
contentType: {
...layout.contentType,
layouts: modifiedLayouts,
}
},
query,
};
};
export default mutateEditViewHook;

I won’t go into the above file too deeply at this point in time but it’s important to note when the hook will be triggered, hasMapFieldEnabled will determine if the field in the current row should or should not have it’s fieldSchema updated to your Plugin’s ID (url-image). We will add this attribute in the next step.

In our new plugin’s admin directory’s index.tsx file src/plugins/url-image/admin/src, we need to import our new hook at the top:

import mutateEditViewHook from "./mutateEditViewHook";

Then register the hook within the bootstrap function:

bootstrap(app) {
app.registerHook(
"Admin/CM/pages/EditView/mutate-edit-view-layout",
mutateEditViewHook
)
},

Our plugin is ready to go.

7 Add the New Field to a Collection Type

In a new or existing collection type /src/api/<collection-id>/content-types/<collection-id>/schema.json, create a new attribute using a string type and add a pluginOptions object like the example below:

"Image": {
"type": "string",
"unique": true,
"required": true,
"pluginOptions": {
"url-image": {
"enabled": true
}
}
}

The pluginOptions attribute will be received by the hook we created in the previous step and mutate the schema to show the new Admin Field Component.

8 Use the New Admin Field Component

With the plugin now activated in the schema.json of your Collection Type, your new component will now appear when creating and editing items in your Strapi Collection Types.

Press enter or click to view image in full size
Screenshot of the URL Image Component being used in the edit form.
Strapi Admin UI showing our new Field Component in use.

Some things to be aware of:

  • Unfortunately at this point in time, you can’t easily add or edit custom admin fields in the Strapi Admin UI, you must manipulate the schema.json file(s) directly.
  • The above example creates a string field in the collection type, which is useful for database creation and migrations.
    - If we used "type": "url-image" in a collection type’s attribute, we would need to write APIs, Database Migrations etc for the new component.
    - It’s simply more accessible if we let Strapi do its thing for this component field.
  • I wrote this article at the time that Strapi was at v4.3.6, things change and can break. Let me know if something has and I’ll update this article accordingly 😅

That’s it, I hope you gained some benefit out of this article and you continue your Strapi journey. If you have any issues, please comment below with feedback including source code and any error messages from your console and browser development tools.

Check out my example project’s source code for the complete solution, including a separate commit outlining all the required changes.

Happy coding!

--

--

Dallas Clark
Dallas Clark

Written by Dallas Clark

Web & Mobile Enthusiast. I’ve worked with some of the world’s most powerful brands, the largest enterprises, and all the different shapes and sizes of startups.

Responses (4)