このコンテンツは選択した言語では利用できません。

Chapter 5. Front-end plugin wiring


You can configure front-end plugins to customize icons, integrate components at mount points, and provide or replace utility APIs.

5.1. Extending internal icon catalog

You can use the internal catalog to fetch icons for configured routes with sidebar navigation menu entry.

Procedure

  • Add a custom icon to the internal icon catalog for use in the menu item of a plugin by using the appIcons configuration as shown in the following example:
# dynamic-plugins-config.yaml
plugins:
  - plugin: <plugin_path_or_url>
    disabled: false
    pluginConfig:
      dynamicPlugins:
        frontend:
          my-plugin:  # The plugin package name
            appIcons:
              - name: fooIcon # The icon catalog name
                # (Optional): The set of assets to access within the plugin. If not specified, the system uses the `PluginRoot` module.
                module: CustomModule
                # (Optional): The actual component name to be rendered as a standalone page. If not specified, the system uses the `default` export.
                importName: FooIcon
Note

The package_name key under dynamicPlugins.frontend must match the scalprum.name value in your plugin’s package.json. This ensures your dynamic plugin loads correctly during runtime.

5.2. Defining dynamic routes for new plugin pages

Procedure

  1. Define each route by specifying a unique path and, if needed, an importName if it is different from the default export.
  2. Expose additional routes in a dynamic plugin by configuring dynamicRoutes as shown in the following example:

    # dynamic-plugins-config.yaml
    plugins:
      - plugin: <plugin_path_or_url>
        disabled: false
        pluginConfig:
          dynamicPlugins:
            frontend:
              my-plugin: # The plugin package name
                dynamicRoutes:
                    # The unique path in the application. The path cannot override existing routes except the `/` home route.
                  - path: /my-plugin
                    # (Optional): The set of assets to access within the plugin. If not specified, the system uses the `PluginRoot` module.
                    module: CustomModule
                    # (Optional): The component name as a standalone page. If not specified, the system uses the `default` export.
                    importName: FooPluginPage
                    # Allows you to extend the main sidebar navigation and point to a new route.
                    menuItem:
                      icon: fooIcon
                      text: Foo Plugin Page
                      enabled: false
                    config: # (Optional): Passes `props` to a custom sidebar item
                      props: ...

    The menuItem accepts the following properties:

    • text: The label shown to the user.
    • icon: The Backstage system icon name.
    • enabled: Optional: Allows the user to remove a menuItem from the sidebar when it is set to false.
    • importName: Specifies the optional name of an exported SidebarItem component.

      To configure a custom SidebarItem to enhance experiences such as notification badges, ensure the component accepts the following properties:

export type MySidebarItemProps = {
  to: string; // supplied by the sidebar during rendering, this will be the path configured for the dynamicRoute
};

Example specifying a custom SidebarItem component:

# dynamic-plugins-config.yaml
plugins:
  - plugin: <plugin_path_or_url>
    disabled: false
    pluginConfig:
      dynamicPlugins:
        frontend:
          my-dynamic-plugin-package-name:
            dynamicRoutes:
              - importName: CustomPage
                menuItem:
                  config:
                    props:
                      text: Click Me!
                  importName: SimpleSidebarItem
                path: /custom_page

5.3. Customizing menu items in the sidebar navigation

You can customize the order and parent-child relationships of plugin menu items in the main sidebar navigation using the menu items configuration as shown in the following example:

# dynamic-plugins-config.yaml
plugins:
  - plugin: <plugin_path_or_url>
    disabled: false
    pluginConfig:
      dynamicPlugins:
        frontend:
          my-plugin: # The plugin package name
            menuItems:
              # The unique name in the main sidebar navigation (for example, either a standalone menu item or a parent menu item)
              <menu_item_name>:
                # (Optional): The icon for the menu item, which refers to a Backstage system icon
                icon: fooIcon
                # (Optional): The display title of the menu item
                title: Foo Plugin Page
                # (Optional): The order in which menu items appear. The default priority is `0`.
                priority: 10
                # (Optional): Defines the parent menu item to nest the current item under
                parent: favorites
                # (Optional): Allows you to remove a `menuItem` from the sidebar when it is set to `false`
                enabled: false

Handling Complex Paths:

  • For simple paths like path: /my-plugin, the menu_item_name should be my-plugin.
  • For complex paths like /metrics/users/info, the menu_item_name should represent the full path in dot notation (for example metrics.users.info).
  • Ignore trailing and leading slashes in paths as follows:

    • For path: /docs, the menu_item_name is docs.
    • For path: /metrics/users, the menu_item_name is metrics.users.
Note

Red Hat Developer Hub supports up to 3 levels of nested menu items.

5.4. Binding to existing plugins

You can bind to existing plugins and their routes, and declare new targets sourced from dynamic plugins as shown in the following routeBindings configuration:

# dynamic-plugins-config.yaml
plugins:
  - plugin: <plugin_path_or_url>
    disabled: false
    pluginConfig:
      dynamicPlugins:
        frontend:
          my-plugin: # The plugin package name
            routeBindings:
              targets: # A new bind target
                  # (Optional): Defaults to importName. Explicit name of the plugin that exposes the bind target.
                - name: barPlugin
                  # (Required): Explicit import name that reference a BackstagePlugin<{}> implementation.
                  importName: barPlugin
                  # # (Optional): Same as key in `scalprum.exposedModules` key in the `package.json` file of the plugin.
                  module: CustomModule
              bindings:
                - bindTarget: "barPlugin.externalRoutes" # (Required): One of the supported or imported bind targets
                  bindMap: #  A required map of route bindings similar to `bind` function options
                    headerLink: "fooPlugin.routes.root"

To configure routeBindings, complete the following steps:

  1. Define new targets using routeBindings.targets. Set the required importName to a BackstagePlugin<{}> implementation.
  2. Declare route bindings using the routeBindings.bindings field by setting bindTarget to the name of the target to bind to. This is a dynamic or static target, such as:

    • catalogPlugin.externalRoutes
    • catalogImportPlugin.externalRoutes
    • techdocsPlugin.externalRoutes
    • scaffolderPlugin.externalRoutes

      You can extend existing pages with additional content using mount points, which are predefined identifiers available throughout the application.

5.5. Using mount points

Mount points are defined identifiers available across Red Hat Developer Hub. You can use these points to extend existing pages with additional content.

5.5.1. Customizing entity page

You can extend catalog components and additional views.

The available mount points include the following:

Expand
Table 5.1. Input parameters
Mount pointDescriptionVisible even when no plugins are enabled

admin.page.plugins

Administration plugins page

NO

admin.page.rbac

Administration RBAC page

NO

entity.context.menu

Catalog entity context menu

YES for all entities

entity.page.overview

Catalog entity overview page

YES for all entities

entity.page.topology

Catalog entity Topology tab

NO

entity.page.issues

Catalog entity Issues tab

NO

entity.page.pull-requests

Catalog entity Pull Requests tab

NO

entity.page.ci

Catalog entity CI tab

NO

entity.page.cd

Catalog entity CD tab

NO

entity.page.kubernetes

Catalog entity Kubernetes tab

NO

entity.page.image-registry

Catalog entity Image Registry tab

NO

entity.page.monitoring

Catalog entity Monitoring tab

NO

entity.page.lighthouse

Catalog entity Lighthouse tab

NO

entity.page.api

Catalog entity API tab

YES for entity of kind: Component and spec.type: 'service'

entity.page.dependencies

Catalog entity Dependencies tab

YES for entity of kind: Component

entity.page.docs

Catalog entity Documentation tab

YES for entity that satisfies isTechDocsAvailable

entity.page.definition

Catalog entity Definitions tab

YES for entity of kind: Api

entity.page.diagram

Catalog entity Diagram tab

YES for entity of kind: System

search.page.types

Search result type

YES, default catalog search type is available

search.page.filters

Search filters

YES, default catalog kind and lifecycle filters are visible

search.page.results

Search results content

YES, default catalog search is present

Note

Mount points within catalog such as entity.page. are rendered as tabs and become visible only if at least one plugin contributes to them, or if they can render static content.

Each entity.page. mount point contains the following variations:

  • /context type that serves to create React contexts
  • /cards type for regular React components

The following is an example of the overall configuration structure of a mount point:

# dynamic-plugins-config.yaml
plugins:
  - plugin: <plugin_path_or_url>
    disabled: false
    pluginConfig:
      dynamicPlugins:
        frontend:
          my-plugin: # The plugin package name
            mountPoints: # (Optional): Uses existing mount points
              - mountPoint: <mountPointName>/[cards|context]
                module: CustomModule
                importName: FooPluginPage
                config: # (Optional): Allows you to pass additional configuration to the component
                  layout: {} # Used only in `/cards` type which renders visible content
                  # Use only in `/cards` type which renders visible content. `if` is passed to `<EntitySwitch.Case if={<here>}`.
                  if:
                    allOf|anyOf|oneOf:
                      - isMyPluginAvailable
                      - isKind: component
                      - isType: service
                      - hasAnnotation: annotationKey
                  props: {} # Useful when you are passing additional data to the component

The available conditions include:

  • allOf: All conditions must be met
  • anyOf: At least one condition must be met
  • oneOf: Only one condition must be met

Conditions are:

  • isKind: Accepts a string or a list of string with entity kinds. For example isKind: component renders the component only for entity of kind: Component.
  • isType: Accepts a string or a list of string with entity types. For example isType: service renders the component only for entities of spec.type: 'service'.
  • hasAnnotation: Accepts a string or a list of string with annotation keys. For example hasAnnotation: my-annotation renders the component only for entities that have defined metadata.annotations['my-annotation'].
  • Condition imported from the module of the plugin: Must be function name exported from the same module within the plugin. For example isMyPluginAvailable renders the component only if isMyPluginAvailable function returns true. The function must have the following signature: (e: Entity) ⇒ boolean.

The entity page supports adding more items to the context menu at the top right of the page. The exported component is a form of dialog wrapper component that accepts an open boolean property and an onClose event handler property as shown in the following example:

export type SimpleDialogProps = {
  open: boolean;
  onClose: () => void;
};

You can configure the context menu entry using the props configuration entry for the mount point. The title and icon properties sets the text and icon of the menu item. You can use any system icon or icon added through a dynamic plugin. The following is an example configuration:

# dynamic-plugins-config.yaml
plugins:
  - plugin: <plugin_path_or_url>
    disabled: false
    pluginConfig:
      dynamicPlugins:
        frontend:
          my-dynamic-plugin-package:
            appIcons:
              - name: dialogIcon
                importName: DialogIcon
            mountPoints:
              - mountPoint: entity.context.menu
                importName: SimpleDialog
                config:
                  props:
                    title: Open Simple Dialog
                    icon: dialogIcon

5.5.2. Adding application header

You can customize global headers by specifying configurations in the app-config.yaml file as shown in the following example:

# app-config.yaml
dynamicPlugins:
  frontend:
    my-plugin:  # The plugin package name
      mountPoints:
        - mountPoint: application/header # Adds the header as a global header
          importName: <header_component> # Specifies the component exported by the global header plugin
          config:
            position: above-main-content # Supported values: (`above-main-content`| above-sidebar`)
Note

To configure multiple global headers at different positions, add entries to the mountPoints field.

5.5.3. Adding application listeners

You can add application listeners using the application/listener mount point as shown in the following example:

# app-config.yaml
dynamicPlugins:
  frontend:
    my-plugin: # The plugin package name
      mountPoints:
        - mountPoint: application/listener
          importName: <exported listener component>
Note

You can configure multiple application listeners by adding entries to the mountPoints field.

5.5.4. Adding application providers

You can add application providers using the application/provider mount point. You can use a mount point to configure a context provider as shown in the following example:

# app-config.yaml
dynamicPlugins:
  frontend:
    my-plugin: # The plugin package name
      dynamicRoutes:
        - path: /<route>
          importName: Component # The component to load on the route
      mountPoints:
        - mountPoint: application/provider
          importName: <exported provider component>
Note
  1. You can configure multiple application providers by adding entries to the mountPoints field.
  2. The package_name key under dynamicPlugins.frontend must match the scalprum.name value in the package.json file of your plugin. This ensures your dynamic plugin loads correctly at runtime.

5.6. Customizing and extending entity tabs

You can customize and extend the set of tabs using the entityTabs configuration as follows:

# dynamic-plugins-config.yaml
plugins:
  - plugin: <plugin_path_or_url>
    disabled: false
    pluginConfig:
      dynamicPlugins:
        frontend:
          my-plugin: # The plugin package name
            entityTabs:
              # Specify a new tab
              - path: /new-path
                title: My New Tab
                mountPoint: entity.page.my-new-tab
              # Change an existing tab's title or mount point
              - path: /
                title: General
                mountPoint: entity.page.overview
                # Specify the sub-path route in the catalog where this tab is available
              - path: "/pr"
                title: "Changed Pull/Merge Requests" # Specify the title you want to display
                priority: 1
                # The base mount point name available on the tab. This name expands to create two mount points per tab, with` /context` and with `/cards`
                mountPoint: "entity.page.pull-requests"
              - path: "/"
                title: "Changed Overview"
                mountPoint: "entity.page.overview"
                # Specify the order of tabs. The tabs with higher priority values appear first
                priority: -6

You can configure dynamic front-end plugins to target the mount points exposed by the entityTabs configuration. The following are the default catalog entity routes in the default order:

Expand
Table 5.2. Input parameters
RouteTitleMount PointEntity Kind

/

Overview

entity.page.overview

Any

/topology

Topology

entity.page.topology

Any

/issues

Issues

entity.page.issues

Any

/pr

CPull/Merge Requests

entity.page.pull-requests

Any

/ci

CI

entity.page.ci`

VAny

/cd

CD

entity.page.cd

Any

/kubernetes

Kubernetes

entity.page.kubernetes

Any

/image-registry

Image Registry

entity.page.image-registry

Any

/monitoring

Monitoring

entity.page.monitoring

Any

/lighthouse

Lighthouse

entity.page.lighthouse

Any

/api

Api

entity.page.api

kind: Service or kind: Component

/dependencies

Dependencies

entity.page.dependencies

kind: Component

/docs

Docs

entity.page.docs

Any

/definition

Definition

entity.page.definition

kind: API

/system

Diagram

entity.page.diagram

kind: System

Note

Mount points within Catalog such as `entity.page.*` are rendered as tabs and become visible only if at least one plugin contributes to them, or if they can render static content.

5.7. Using a custom SignInPage component

In Red Hat Developer Hub (RHDH), the SignInPage component manages the authentication flow of the application. This component connects one or more authentication providers to the sign-in process. By default, Developer Hub uses a static SignInPage that supports all built-in authentication providers.

When you configure a custom SignInPage:

  • The system loads the specified importName component from your dynamic plugin.
  • The component returns a configured SignInPage that connects the desired authentication provider factories.
  • Only one signInPage is specified for the application at a time.
dynamicPlugins:
  frontend:
    my-plugin: # The plugin package name
      signInPage:
        importName: CustomSignInPage
Note

The package_name specified under dynamicPlugins.frontend must match the scalprum.name value in the package.json file of your plugin to ensure the dynamic plugin loads correctly at runtime.

The module field is optional and allows specifying which set of assets must be accessed within the dynamic plugin. By default, the system uses the PluginRoot module.

5.8. Providing custom Scaffolder field extensions

The Scaffolder component in Red Hat Developer Hub (RHDH) enables users to create software components using templates through a guided wizard. You can extend the functionality of the Scaffolder by providing custom form fields as dynamic plugins using the scaffolderFieldExtensions configuration.

Custom field extensions allow you to add specialized form fields that capture domain-specific data during the scaffolding process, such as environment selectors, input validations, or repository checks.

When you configure custom scaffolder field extensions:

  • The dynamic plugin exposes the field extension component using createScaffolderFieldExtension.
  • Each field extension requires a unique importName for registration.
  • You register multiple field extensions by listing each in the configuration.
dynamicPlugins:
  frontend:
    my-plugin: # The plugin package name
      scaffolderFieldExtensions:
        - importName: MyNewFieldExtension # References the exported scaffolder field extension component from your plugin
Note

The module field is optional and specifies which set of assets to access within the plugin. By default, the system uses the PluginRoot module, consistent with the scalprum.exposedModules key in the package.json file of your package.

5.9. Provide additional utility APIs

If a dynamic plugin exports the plugin object returned by createPlugin, it is supplied to the createApp API. All API factories exported by the plugin are automatically registered and available in the front-end application.

You can add an entry to the dynamicPlugins.frontend configuration when a dynamic plugin contains only API factories as shown in the following example:

# app-config.yaml
dynamicPlugins:
  frontend:
    my-dynamic-plugin-package-with-api-factories: {}

However, when the dynamic plugin is not exporting the plugin object, explicitly configure each API factory that must be registered with the createApp API using the apiFactories configuration as shown in the following example:

# app-config.yaml
dynamicPlugins:
  frontend:
    my-plugin: # The plugin package name
      apiFactories:
        # (Optional): Specify the import name that references a `AnyApiFactory<{}>` implementation. (Defaults to `default` export)
        - importName: BarApi
          # (Optional): An argument which specifies the assets you want to access within the plugin. If not provided, the default module named `PluginRoot` is used
          module: CustomModule

The API factories initialized by the Developer Hub application shell are overridden by an API factory provided by a dynamic plugin by specifying the same API ref ID. A dynamic plugin can export AnyApiFactory<{}> to cater for some specific use case as shown in the following example:

export const customScmAuthApiFactory = createApiFactory({
  api: scmAuthApiRef,
  deps: { githubAuthApi: githubAuthApiRef },
  factory: ({ githubAuthApi }) =>
    ScmAuth.merge(
      ScmAuth.forGithub(githubAuthApi, { host: "github.someinstance.com" }),
      ScmAuth.forGithub(githubAuthApi, {
        host: "github.someotherinstance.com",
      }),
    ),
});

The corresponding configuration which overrides the default ScmAuth API factory that Developer Hub defaults to is as shown in the following example:

dynamicPlugins:
  frontend:
    my-plugin:  # The plugin package name
      apiFactories:
        - importName: customScmAuthApiFactory

5.10. Adding custom authentication provider settings

You can install new authentication providers from a dynamic plugin that either adds additional configuration support for an existing provider or adds a new authentication provider. These providers are listed in the user settings section under the Authentication Providers tab.

You can use the providerSettings configuration to add entries for an authentication provider from a dynamic plugin, as shown in the following example:

dynamicPlugins:
  frontend:
    my-plugin: # The plugin package name
      providerSettings:
        # The title for the authentication provider shown above the user's profile image if available
        - title: My Custom Auth Provider
          # The description of the authentication provider
          description: Sign in using My Custom Auth Provider
          # The ID of the authentication provider as provided to the `createApiRef` API call.
          provider: core.auth.my-custom-auth-provider
Note

provider looks up the corresponding API factory for the authentication provider to connect the provider’s Sign In/Sign Out button.

5.11. Provide custom TechDocs addons

If a plugin provides multiple addons, each techdocsAddon entry specifies a unique importName corresponding to the addon. Front-end plugins exposes the TechDocs addon component using the techdocsAddons configuration as shown in the following example:

dynamicPlugins:
  frontend:
    my-plugin: # The plugin package name
      techdocsAddons:
        - importName: ExampleAddon # The exported Addon component
          config:
            props: ... # (Optional): React props to pass to the addon

5.12. Customizing Red Hat Developer Hub theme

You can customize Developer Hub themes from a dynamic plugin with various configurations as shown in the following example:

import { lightTheme } from './lightTheme';
import { darkTheme } from './darkTheme';
import { UnifiedThemeProvider } from '@backstage/theme';
export const lightThemeProvider = ({ children }: { children: ReactNode }) => (
  <UnifiedThemeProvider theme={lightTheme} children={children} />
);
export const darkThemeProvider = ({ children }: { children: ReactNode }) => (
  <UnifiedThemeProvider theme={darkTheme} children={children} />
);

For more information about creating a custom theme, see creating a custom theme.

You can declare the theme using the themes configuration as shown in the following example:

dynamicPlugins:
  frontend:
    my-plugin: # The plugin package name
      themes:
          #  are `light` or `dark`. Using 'light' overrides the app-provided light theme
        - id: light
          title: Light
          variant: light
          icon: someIconReference
          importName: lightThemeProvider
          # The theme name displayed to the user on the *Settings* page. Using 'dark' overrides the app-provided dark theme
        - id: dark
          title: Dark
          variant: dark
          icon: someIconReference # A string reference to a system or app icon
          # The name of the exported theme provider function, the function signature should match `({ children }: { children: ReactNode }): React.JSX.Element`
          importName: darkThemeProvider
Red Hat logoGithubredditYoutubeTwitter

詳細情報

試用、購入および販売

コミュニティー

会社概要

Red Hat は、企業がコアとなるデータセンターからネットワークエッジに至るまで、各種プラットフォームや環境全体で作業を簡素化できるように、強化されたソリューションを提供しています。

多様性を受け入れるオープンソースの強化

Red Hat では、コード、ドキュメント、Web プロパティーにおける配慮に欠ける用語の置き換えに取り組んでいます。このような変更は、段階的に実施される予定です。詳細情報: Red Hat ブログ.

Red Hat ドキュメントについて

Legal Notice

Theme

© 2026 Red Hat
トップに戻る