Skip to main content

Admin Panel API: Injection zones

Page summary:

Injection zones are predefined areas in the admin UI where plugins can inject React components. Use getPlugin('content-manager').injectComponent() to extend built-in views, or define your own zones with injectionZones in registerPlugin.

Plugins can extend and customize existing admin panel sections by injecting custom React components into predefined areas. This allows you to add functionality to Strapi's built-in interfaces without modifying core code.

Prerequisites

Before diving deeper into the concepts on this page, please ensure you have:

Note

Injection zones are defined in the register lifecycle function, but components are injected in the bootstrap lifecycle function.

Injection zones vs. Content Manager APIs

tl;dr

For adding panels, actions, or buttons to the Content Manager, the Content Manager APIs (addDocumentAction, addEditViewSidePanel, etc.) are often more robust and better typed than injection zones. Use injection zones when you need to insert components into specific UI areas not covered by the Content Manager APIs.

Content Manager APIs and injection zones are both extension points to customize the admin panel, but they solve different needs:

NeedRecommended APIWhy
Add a custom panel in the Edit View side areaContent Manager API (addEditViewSidePanel)Best for contextual information or controls that stay visible while editing.
Add actions in a document action menuContent Manager API (addDocumentAction)Best for document-level actions in the Edit View actions menu.
Add actions in the Edit View headerContent Manager API (addDocumentHeaderAction)Best for quick, prominent actions next to the document title.
Add actions for selected entries in List ViewContent Manager API (addBulkAction)Best for workflows that apply to multiple entries at once.
Add UI to a predefined zone in a plugin view (localized visual customization)Injection Zones API (injectComponent)Best when you target a specific zone exposed by a plugin.

For implementation details and up-to-date API signatures, please refer to the content-manager file in the Strapi codebase.

Mini examples (inside bootstrap(app))

// Document action menu item
app.getPlugin('content-manager').apis.addDocumentAction(() => ({
label: 'Run custom action',
onClick: ({ documentId }) => runCustomAction(documentId),
}));

// Edit View header action
app.getPlugin('content-manager').apis.addDocumentHeaderAction(() => ({
label: 'Open preview',
onClick: ({ document }) => openPreview(document),
}));

// List View bulk action
app.getPlugin('content-manager').apis.addBulkAction(() => ({
label: 'Bulk publish',
onClick: ({ documentIds }) => bulkPublish(documentIds),
}));

// Edit View side panel
app.getPlugin('content-manager').apis.addEditViewSidePanel([
{
name: 'my-plugin.side-panel',
Component: MySidePanel,
},
]);

// Injection zone (plugin-defined zone)
app.getPlugin('content-manager').injectComponent('editView', 'right-links', {
name: 'my-plugin.custom-link',
Component: MyCustomLink,
});

Predefined injection zones

Strapi's Content Manager provides predefined injection zones that plugins can use:

ViewInjection zoneLocation
List viewlistView.actionsBetween the Filters and the cogs icon
List viewlistView.publishModalAdditionalInfosInformational content in the publish confirmation modal
List viewlistView.unpublishModalAdditionalInfosInformational content in the unpublish confirmation modal
List viewlistView.deleteModalAdditionalInfosInformational content in the delete confirmation modal
Edit vieweditView.right-linksBetween the "Configure the view" and "Edit" buttons
Edit vieweditView.informationsIn the informations box of the Edit view (internal, see note below)
Previewpreview.actionsIn the preview view action area

The listView.*ModalAdditionalInfos zones are intended to enrich the informational content displayed in publish, unpublish, and delete confirmation modals.

Caution

The editView.informations zone exists in the Content Manager source code but is considered internal. For third-party plugins, editView.right-links is the most stable and officially recommended Edit view extension point. Use editView.informations only when you specifically need the information panel area and accept potential UI changes between versions.

Injecting into Content Manager zones

To inject a component into a Content Manager injection zone, use getPlugin('content-manager').injectComponent() in the bootstrap lifecycle:

admin/src/index.js
import { MyCustomButton } from './components/MyCustomButton';
import { PreviewAction } from './components/PreviewAction';
import { PublishModalInfo } from './components/PublishModalInfo';

export default {
register(app) {
app.registerPlugin({
id: 'my-plugin',
name: 'My Plugin',
});
},
bootstrap(app) {
// Inject a button into the Edit view's right-links zone
app
.getPlugin('content-manager')
.injectComponent('editView', 'right-links', {
name: 'my-plugin-custom-button',
Component: MyCustomButton,
});

// Inject a component into the List view's actions zone
app
.getPlugin('content-manager')
.injectComponent('listView', 'actions', {
name: 'my-plugin-list-action',
Component: () => <button>Custom List Action</button>,
});

// Inject additional information into the publish modal
app
.getPlugin('content-manager')
.injectComponent('listView', 'publishModalAdditionalInfos', {
name: 'my-plugin-publish-modal-info',
Component: PublishModalInfo,
});

// Inject a component into the Preview view's actions zone
app
.getPlugin('content-manager')
.injectComponent('preview', 'actions', {
name: 'my-plugin-preview-action',
Component: PreviewAction,
});
},
};

Custom injection zones

Plugins can define their own injection zones to allow other plugins to extend their UI. Declare injection zones in the registerPlugin configuration:

admin/src/index.js
export default {
register(app) {
app.registerPlugin({
id: 'dashboard',
name: 'Dashboard',
injectionZones: {
homePage: {
top: [],
middle: [],
bottom: [],
},
sidebar: {
before: [],
after: [],
},
},
});
},
};

Rendering injection zones in components

In Strapi 5, the InjectionZone component from @strapi/helper-plugin is removed and has no direct replacement export. To render injected components, create your own component with useStrapiApp from @strapi/strapi/admin.

admin/src/components/CustomInjectionZone.jsx
import { useStrapiApp } from '@strapi/strapi/admin';

export const CustomInjectionZone = ({ area, ...props }) => {
const getPlugin = useStrapiApp('CustomInjectionZone', (state) => state.getPlugin);
const [pluginName, view, zone] = area.split('.');

const plugin = getPlugin(pluginName);
const components = plugin?.getInjectedComponents(view, zone);

if (!components?.length) {
return null;
}

return components.map(({ name, Component }) => <Component key={name} {...props} />);
};
admin/src/pages/Dashboard.jsx
import { CustomInjectionZone } from '../components/CustomInjectionZone';

const Dashboard = () => {
return (
<div>
<h1>Dashboard</h1>

{/* Render components injected into the top zone */}
<CustomInjectionZone area="dashboard.homePage.top" />

<div className="main-content">{/* Main dashboard content */}</div>

{/* Render components injected into the bottom zone */}
<CustomInjectionZone area="dashboard.homePage.bottom" />
</div>
);
};

export default Dashboard;

Injecting into custom zones

Other plugins can inject components into your custom injection zones using the injectComponent() method in their bootstrap lifecycle:

another-plugin/admin/src/index.js
import { Widget } from './components/Widget';

export default {
register(app) {
app.registerPlugin({
id: 'widget-plugin',
name: 'Widget Plugin',
});
},
bootstrap(app) {
const dashboardPlugin = app.getPlugin('dashboard');

if (dashboardPlugin) {
dashboardPlugin.injectComponent('homePage', 'top', {
name: 'widget-plugin-statistics',
Component: Widget,
});
}
},
};

Injection component parameters

The injectComponent() method accepts the following parameters:

ParameterTypeDescription
viewstringThe view name where the component should be injected
zonestringThe zone name within the view where the component should be injected
componentobjectConfiguration object with name (unique string) and Component (React component to inject)

Content Manager data access

When injecting components into Content Manager injection zones, you can access the Edit View data using the useContentManagerContext hook:

admin/src/components/MyCustomButton.jsx
import {
unstable_useContentManagerContext as useContentManagerContext,
} from '@strapi/strapi/admin';

export const MyCustomButton = () => {
const {
slug, // Content type slug (e.g., 'api::article.article')
model, // Content type model
id, // Document ID (undefined when creating)
collectionType, // 'single-types' or 'collection-types'
isCreatingEntry, // Whether creating a new entry
isSingleType, // Whether the content type is a single type
hasDraftAndPublish, // Whether draft & publish is enabled
contentType, // Content type schema
components, // Component schemas
layout, // Content type layout
form, // Form state and handlers
} = useContentManagerContext();

const { initialValues, values, onChange } = form;

const handleCustomAction = () => {
onChange({ target: { name: 'customField', value: 'new value' } });
};

return <button onClick={handleCustomAction}>Custom Action</button>;
};
Caution

The useContentManagerContext hook is currently exported as unstable_useContentManagerContext. The unstable_ prefix indicates the API may change in future releases. This hook replaces the deprecated useCMEditViewDataManager from @strapi/helper-plugin which is not available in Strapi 5.

Best practices

  • Use descriptive zone names. Choose clear names for your injection zones (e.g., top, bottom, before, after).

  • Check plugin availability. Always verify that a plugin exists before injecting components into its zones:

    bootstrap(app) {
    const targetPlugin = app.getPlugin('target-plugin');
    if (targetPlugin) {
    targetPlugin.injectComponent('view', 'zone', {
    name: 'my-component',
    Component: MyComponent,
    });
    }
    }
  • Use unique component names. Ensure component names are unique to avoid conflicts with other plugins.

  • Handle missing zones gracefully. Components should handle cases where injection zones might not be available.

  • Document your injection zones. Clearly document which injection zones your plugin provides and their intended use.