Admin Panel API: Navigation & settings
Page summary:
Use
addMenuLinkinregisterto add sidebar links,createSettingSectioninregisterto create settings groups, andaddSettingsLink/addSettingsLinksinbootstrapto extend existing settings sections.
Plugins can customize the admin panel's navigation sidebar and settings pages to provide access to their features. All functions described on this page are called within the register or bootstrap lifecycle functions of your plugin's entry file.
Before diving deeper into the concepts on this page, please ensure you have:
- created a Strapi plugin,
- read and understood the basics of the Admin Panel API
Navigation sidebar (menu links)
The navigation sidebar is the main menu on the left side of the admin panel. Plugins can add links to this sidebar using the addMenuLink() method in the register lifecycle function.
Adding a menu link
Adding a link to the navigation sidebar is done with the addMenuLink() function, which should be registered through the register() lifecycle function of your plugin.
A menu link accepts the following parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
to | string | ✅ | Path the link should point to (relative to the admin panel root) (see additional information) |
icon | React.Component | ✅ | React component for the icon to display in the navigation |
intlLabel | object | ✅ | Label for the link, following the React Int'l convention, with:
|
Component | async function | ✅ | Async function that returns a dynamic import of the plugin's main page component |
permissions | Array<object> | ❌ | Array of permission objects that control access to the link |
position | number | ❌ | Numeric position in the menu (lower numbers appear first) |
licenseOnly | boolean | ❌ | If true, displays a ⚡ icon to indicate the feature requires a paid license (default: false) |
The intlLabel.id values should correspond to keys in your translation files located at admin/src/translations/[locale].json. See Admin localization for details.
The permissions parameter only controls whether the link is visible in the navigation. It does not protect the page itself. A user who knows the URL can still access the page directly. To fully secure a plugin route, you must also check permissions inside your page component and register your RBAC actions on the server side with actionProvider.registerMany. See the Admin permissions for plugins guide for a complete walkthrough.
- JavaScript
- TypeScript
import PluginIcon from './components/PluginIcon';
export default {
register(app) {
app.addMenuLink({
to: `/plugins/my-plugin`,
icon: PluginIcon,
intlLabel: {
id: 'my-plugin.plugin.name',
defaultMessage: 'My Plugin',
},
Component: async () => {
const { App } = await import('./pages/App');
return App;
},
permissions: [], // Array of permission objects
position: 3, // Position in the menu (lower numbers appear first)
licenseOnly: false, // Set to true to show ⚡ icon for paid features
});
app.registerPlugin({
id: 'my-plugin',
name: 'My Plugin',
});
},
};
import PluginIcon from './components/PluginIcon';
import type { StrapiApp } from '@strapi/admin/strapi-admin';
export default {
register(app: StrapiApp) {
app.addMenuLink({
to: `/plugins/my-plugin`,
icon: PluginIcon,
intlLabel: {
id: 'my-plugin.plugin.name',
defaultMessage: 'My Plugin',
},
Component: async () => {
const { App } = await import('./pages/App');
return App;
},
permissions: [], // Array of permission objects
position: 3, // Position in the menu (lower numbers appear first)
licenseOnly: false, // Set to true to show ⚡ icon for paid features
});
app.registerPlugin({
id: 'my-plugin',
name: 'My Plugin',
});
},
};
Settings
The Settings API allows plugins to create new settings sections or add links to existing sections. Settings sections are organized groups of configuration pages accessible from the Settings menu item in the navigation sidebar.
Creating a new settings section
Use createSettingSection() in the register lifecycle function:
- JavaScript
- TypeScript
export default {
register(app) {
app.createSettingSection(
{
id: 'my-plugin',
intlLabel: {
id: 'my-plugin.settings.section-label',
defaultMessage: 'My Plugin Settings',
},
},
[
{
intlLabel: {
id: 'my-plugin.settings.general',
defaultMessage: 'General',
},
id: 'general',
to: 'my-plugin/general',
Component: async () => {
const { GeneralSettings } =
await import('./pages/Settings/General');
return GeneralSettings;
},
},
{
intlLabel: {
id: 'my-plugin.settings.advanced',
defaultMessage: 'Advanced',
},
id: 'advanced',
to: 'my-plugin/advanced',
Component: async () => {
const { AdvancedSettings } =
await import('./pages/Settings/Advanced');
return AdvancedSettings;
},
},
],
);
app.registerPlugin({
id: 'my-plugin',
name: 'My Plugin',
});
},
};
import type { StrapiApp } from '@strapi/admin/strapi-admin';
export default {
register(app: StrapiApp) {
app.createSettingSection(
{
id: 'my-plugin',
intlLabel: {
id: 'my-plugin.settings.section-label',
defaultMessage: 'My Plugin Settings',
},
},
[
{
intlLabel: {
id: 'my-plugin.settings.general',
defaultMessage: 'General',
},
id: 'general',
to: 'my-plugin/general',
Component: async () => {
const { GeneralSettings } =
await import('./pages/Settings/General');
return GeneralSettings;
},
},
{
intlLabel: {
id: 'my-plugin.settings.advanced',
defaultMessage: 'Advanced',
},
id: 'advanced',
to: 'my-plugin/advanced',
Component: async () => {
const { AdvancedSettings } =
await import('./pages/Settings/Advanced');
return AdvancedSettings;
},
},
],
);
app.registerPlugin({
id: 'my-plugin',
name: 'My Plugin',
});
},
};
The createSettingSection() function accepts the following parameters:
-
the first argument is the section configuration:
Parameter Type Required Description idstring✅ Unique identifier for the settings section intlLabelobject✅ Localized label for the section, following the React Int'l convention, with: id: id used to insert the localized labeldefaultMessage: default label for the section
-
the second argument is an array of link objects; each link object contains the following:
Parameter Type Required Description idstring