Can I use this?
In order to follow this guide, you must use Webiny version 5.13.0 or greater.
What you'll learn
- how the navigation menu works
- how to add, remove, and modify menu items in the navigation menu
Good to know
If you're not already familiar with the Webiny UI Composer, we recommend familiarizing yourself with the concept before moving on with this guide.
To use the instructions presented in this guide, you need to know how to register Webiny plugins in your React applications. Please visit the Importing Plugins guide, if you're not already familiar with the process.
Navigation within the Admin Area application is implemented using the
NavigationView view class. It is built using the UI Composer. This means that you can hook into any part of the view and modify it.
In this article, we cover some common customizations you might need for your project.
NavigationView view has a certain structure: it has a header element, a content element, and a footer element (marked with purple boxes in the image below).
The purpose of these sections is to provide a developer-friendly interface for customization, as well as establish sensible defaults for rendering of menu items.
For example, all menu items within the content section are sorted by tags (tags are explained in the next section), then alphabetically. The footer section only sorts menu items alphabetically.
All menu items are created using the
NavigationMenuElement element class. This element class has several renderers assigned to it, and depending on the location in the hierarchy of the navigation view, the appropriate renderer will be used to render each individual element.
To learn how renderers within the UI Composer work, read the article on Creating Elements.
To add menu items to the navigation view,
NavigationView class exposes 3 helper methods:
addAppMenuElement(element: NavigationMenuElement)- adds the given element to the content section of the navigation view, and tags it with an
addUtilityMenuElement(element: NavigationMenuElement)- adds the given element to the content section of the navigation view, and tags it with a
addSettingsMenuElement(element: NavigationMenuElement)- adds the given element to the Settings menu. By default, these items will be on a second level in the hierarchy, so we don't need to tag them.
Tags are used to differentiate between menu item's "importance". By default, we use the
utils tag, but you can easily introduce your own tags for your new menu items.
These helper methods are there for you to make adding of menu items as straightforward as possible. You can still use the low-level API of the UI Composer, if you have to.
There are 2 menu item sorters configured for the content section of the navigation view, out of the box. First we sort items by "importance", then alphabetically. These sorters are configurable, and you can implement your own sorting logic (covered later in the article).
As we mentioned in the previous section, menu items get tagged. With an
app tag, we tell the navigation view that this menu item represents an application, and it needs to be at the top of all other "less important" menu items. Menu items tagged with a
utils tag will be rendered at the bottom (for example, the
In this example, we add a new application menu item, called Github, then create a new section called Repositories, and add two links within that section.
With this plugin, we created a menu group
Github, a menu section
Repositories, and two links.
In this example, we remove the Form Builder menu item from the navigation. This same technique can be applied to any element.
First, we need to find the ID of the element. To do that, we need to open React Dev Tools, and find the corresponding
<ElementID>. The element class and its ID will be printed in the
key prop, separated by a colon.
In our case, it will be
NavigationMenuElement:navigation.content.app-form-builder, which means it is an element of class
NavigationMenuElement and it has an ID of
Now we can implement a plugin, and remove the element.
This is the first time we encountered an asynchronous callback. We're waiting for the first render to happen. Why is that necessary?
It depends on the complexity and hierarchy of the view. Keep in mind that plugins are applied to their corresponding classes at instantiation time (right at the end of the class constructor execution), and when it's a complex element, with child elements, it's very likely that parent element was not yet assigned, meaning that the parent/child hierarchy is not yet established.
You can, in general, use the
await view.isRendered() in all of your plugins, to be on the safe side.
In this example, we add a custom menu item renderer, to support links as top level menu items in the content section of the navigation view (by default, we only support menu groups). This custom renderer will be taken into consideration for all menu item elements that are created using the
We need to set some constraints to apply this new renderer in an optimal way, and not override an existing renderer by accident. Let's establish that we only want this renderer to apply to menu items that are in the content section of the navigation view, the item has to be the top-level item, and it must have the
path config set (this can be both local route and an external URL).
The renderer is ready. Now we need to add it to the
NavigationMenuElement class. We can hook into any element class by using the
This will result in our new menu item being rendered with the new custom renderer.
This example shows how you can apply the same renderer we created earlier, but in a local manner, so that it only handles a particular instance of a menu item, and is the only renderer that will be executed for that menu.
The styling code is skipped to make the example shorter. Use the styling code from the previous example, if you don't already have it.
There are cases where this pattern is very useful, especially because you don't need to think about conditions that need to be matched. A good example of this pattern is our File Manager menu item, where we need to wrap the menu item with a File Manager component.
With custom menu items, you may want to break out of the built-in sorting rules. There's an easy way to add your own sorting logic on top of the default one. Let's go back to the menu item registration, and add a custom sorter using tags.
In this example, we're splitting the logic into several plugins, to clearly show responsibilities of each plugin.
As a result, the navigation now looks like this:
In this example we'll replace the header section with a custom component, and we'll also completely remove the footer.
GenericElement is a utility element class that serves as an escape hatch when you need to mount a React component just once. Usually, we recommend always creating a dedicated n element class for every React component, but sometimes it's just not worth the effort. Like in this example, where we just want to mount one simple component, and move on.
The result of these simple manipulations looks like this:
Absolutely anything! Following these examples, you can build all kinds of custom menu items. What you render in your renderers is entirely up to you, it doesn't even have to be a link, or a traditional menu. Any React component will do: buttons, calendars, charts - it's up to your project requirements.