Router Layouts and Nested Router Targets

RouterLayout Interface

All parent layouts of a navigation target component must implement the RouterLayout interface.

You can define a parent layout using the Route.layout() method.

Example: Render CompanyComponent inside MainLayout:

@Tag("div")
@Route(value = "company", layout = MainLayout.class)
public class CompanyComponent extends Component {
}
Note
When using the @Route("path") annotation to define a route, the component by default renders in the <body> tag on the page. This is because the element returned by HasElement.getElement() is attached to the <body> tag.

Multiple Router Target Components

Where multiple router target components use the same parent layout, the parent layout instances remain the same when the user navigates between the child components.

Multiple Parent Layouts

Use the @ParentLayout annotation to define a parent layout for components in the routing hierarchy.

You can create a parent layout for a parent layout, where necessary.

Example: MainLayout used for everything and MenuBar reused for views:

public class MainLayout extends Div
        implements RouterLayout {
}

@ParentLayout(MainLayout.class)
public class MenuBar extends Div
        implements RouterLayout {
    public MenuBar() {
        addMenuElement(TutorialView.class, "Tutorial");
        addMenuElement(IconsView.class, "Icons");
    }
    private void addMenuElement(
            Class<? extends Component> navigationTarget,
            String name) {
        // implementation omitted
    }
}

@Route(value = "tutorial", layout = MenuBar.class)
public class TutorialView extends Div {
}

@Route(value = "icons", layout = MenuBar.class)
public class IconsView extends Div {
}
  • MainLayout encapsulates MenuBar, which in turn encapsulates TutorialView or IconsView depending on where the user has navigated to.

ParentLayout Route Control

A parent layout can supplement the navigation route by adding to the route location.

This is done by annotating the parent layout with @RoutePrefix("prefix_to_add")

Example: PathComponent receives the some/path route.

@Route(value = "path", layout = SomeParent.class)
public class PathComponent extends Div {
    // Implementation omitted
}

@RoutePrefix("some")
public class SomeParent extends Div
        implements RouterLayout {
    // Implementation omitted
}

Absolute Routes

You can use same parent component in many parts, without using a @RoutePrefix from the parent chain, or by only using it in defined parts.

This is done by adding absolute = true to either the @Route or @RoutePrefix annotations.

Example: Building a MyContent class to add "something" to multiple places in the SomeParent layout, without adding the route prefix to the navigation path:

@Route(value = "content", layout = SomeParent.class,
       absolute = true)
public class MyContent extends Div {
    // Implementation omitted
}
  • Even though the full path would typically be some/content, we actually get only content because it has been defined as absolute.

Example: Defining absolute in the middle of the chain.

@RoutePrefix(value = "framework", absolute = true)
@ParentLayout(SomeParent.class)
public class FrameworkSite extends Div
        implements RouterLayout {
    // Implementation omitted
}

@Route(value = "tutorial", layout = FrameworkSite.class)
public class Tutorials extends Div {
    // Implementation omitted
}
  • The bound route is framework/tutorial even though the full chain is some/framework/tutorial.

  • If a parent layout defines a @RoutePrefix, the "default" child could have its route defined as @Route("") and be mapped to the parent layout route. For example, in the case of Tutorials with route "" it would be mapped as framework/.