Add a Navigation Menu
- Copy-Paste into Your Project
- Creating a Navigation Menu
- Getting the Menu Items Dynamically
- Icons in the Menu
- Displaying the Current View Title
- Translating Titles and Menu Items
This guide teaches you how to add a navigation menu to a router layout in Vaadin. It is a continuation of the Add a Router Layout guide.
Copy-Paste into Your Project
If you want to quickly try out a navigation menu, you can copy-paste the following code into your router layout:
Source code
MainLayout.java
Expand the code for a complete implementation of a router layout with a navigation menu. For more detailed instructions on how to use build a navigation menu, continue reading below.
Creating a Navigation Menu
You typically build a navigation menu in Vaadin using the Side Navigation components, which provide a vertical list of navigation links with support for collapsible, nested sections. This guide only covers the very basics of building a navigation menu. For more detailed information, see the Side Navigation documentation.
Start by creating an instance of SideNav to act as the container for the navigation items:
Source code
Java
private SideNav createSideNav() {
SideNav sideNav = new SideNav();
// Add navigation items here
return sideNav;
}For every item in the navigation menu, create an instance of SideNavItem, and add it to the SideNav instance. Each item represents a link to a view in your application. You can create a simple navigation item like this:
Source code
Java
SideNavItem homeItem = new SideNavItem("Home", HomeView.class);
sideNav.addItem(homeItem);Now, whenever the user clicks on the item, the router navigates to the specified view. Furthermore, the item is highlighted when the user is on that view.
Highlighting Nested Views
By default, a SideNavItem is highlighted only when the user is on the exact path of the view. That means that if the view has e.g. a URL parameter, or acts as a parent layout for another view, the item is not highlighted.
For example, an item with the path /customers has the following behavior:
-
/customers— item is highlighted -
/customers/123— item is not highlighted -
/customers/123/edit— item is not highlighted
To highlight the item for all paths that start with the view’s path, use the SideNavItem.setMatchNested() method:
Source code
Java
SideNavItem customersItem = new SideNavItem("Customers", CustomersView.class);
customersItem.setMatchNested(true);
// Now matches /customers, /customers/123, /customers/123/edit, etc.
sideNav.addItem(customersItem);Getting the Menu Items Dynamically
If your views have navigation menu items defined using the @Menu annotation, you can build the menu dynamically.
The MenuConfiguration.getMenuEntries() method returns a list of all menu entries defined in the application. You can iterate over these entries and create corresponding SideNavItem instances for each entry:
Source code
Java
private SideNav createSideNav() {
var nav = new SideNav();
MenuConfiguration.getMenuEntries()
.forEach(entry -> nav.addItem(
new SideNavItem(
entry.title(),
entry.menuClass()
)
));
return nav;
}For technical details, see the Menu Configuration reference guide.
Showing Only Accessible Views
MenuConfiguration.getMenuEntries() leaves out the views that the current user can’t open. It checks each view against the same access rules that protect the view itself. For example, a user without the ADMIN role doesn’t get a menu item for a view annotated with @RolesAllowed("ADMIN"). It also leaves out views whose routes have required parameters, because a menu item has no values to give them.
Menu items that you create yourself are shown to every user. To hide one, check the roles of the user with AuthenticationContext, as described in Checking the Roles of the Current User.
A hidden menu item doesn’t protect its view: a user can still type the URL in the address bar. Every view needs access rules of its own.
Icons in the Menu
You often want to have icons in your navigation menu to improve usability and visual appeal. The @Menu annotation has an icon attribute, but it’s an ordinary string. Therefore, you need to decide how to interpret that string in your menu implementation.
For example, if you use Vaadin Icons, you can create an icon for a menu item like this:
Source code
Java
// Annotation on view:
@Menu(title = "Dashboard", icon = "vaadin:dashboard")
// In the menu building code:
item.setPrefixComponent(new Icon(menuEntry.icon()));If you’re using SVG icons, you can do this instead:
Source code
Java
// Annotation on view:
@Menu(title = "Dashboard", icon = "icons/dashboard.svg")
// In the menu building code:
item.setPrefixComponent(new SvgIcon(menuEntry.icon()));Displaying the Current View Title
A common pattern is to display the title of the current view in the layout header. To do this, implement AfterNavigationObserver in your layout and read the @PageTitle annotation from the current view.
Source code
Java
public class MainLayout extends AppLayout implements AfterNavigationObserver {
private final H1 viewTitle = new H1();
public MainLayout() {
addToNavbar(new DrawerToggle(), viewTitle);
// ... rest of setup
}
@Override
public void afterNavigation(AfterNavigationEvent event) {
viewTitle.setText(getCurrentPageTitle());
}
private String getCurrentPageTitle() {
PageTitle title = getContent().getClass().getAnnotation(PageTitle.class);
return title == null ? "" : title.value();
}
}For this to work, views need to declare their titles using the @PageTitle annotation. See Page Title for more details on setting page titles.
Translating Titles and Menu Items
If your application supports several languages, use translation keys as the @PageTitle values, and translate them with an application-wide page title generator:
Source code
Java
@Bean
PageTitleGenerator pageTitleGenerator() {
return context -> I18NProvider.translate(context.value()); 1
}-
context.value()is the@PageTitlevalue of the view, such asorders.title.
The generator applies to every view, so give every view a @PageTitle key. For a view without one, context.value() is empty.
The generator gives the browser tab its title. MenuConfiguration.getMenuEntries() also uses it for every view whose @Menu annotation has no title, so the menu items are translated as well. MenuConfiguration.getPageHeader(getContent()) returns the translated title, too. Call it in the layout instead of reading the @PageTitle annotation as in Displaying the Current View Title.
The layout builds the menu when it’s created. If users can change the language while the application is open, rebuild the menu when the locale changes. See Generating Page Titles for the generator, and the Localization reference for translation files, language selection, and reacting to locale changes.