Router Layouts & Nested Router Targets
All parent layouts of a navigation target component have to implement the RouterLayout
interface. You can define a parent layout by adding the @Layout
annotation to the class, or by using the optional element layout
from the @Route
annotation.
Automatic Layout Using @Layout
The value for the @Layout
annotation path has to be unique for the project. Otherwise, the resolver won’t be able to determine which layout component should be used. Having multiple @Layout
annotations with the same path throws an exception.
The example below renders all routes inside MainLayout
:
@Layout
public class MainLayout extends Div
implements RouterLayout {
}
If the application is using access protection, the view access is checked for the Layout, as well as the view. To make the layout accessible, add @AnonymousAllowed
— or some other access annotation — on the MainLayout
so that the request is not denied.
@Route
and @RouteAlias
each contain an annotation attribute called, autoLayout
. Setting that attribute to false will stop automatic layout; it will ignore any @Layout
matching the route. Giving a class for the layout
method in @Route
also disables automatic layout and uses the one given.
@Route(autoLayout = false)
public class NoLayoutView extends Div {
}
@Route(layout = MyLayout.class)
public class DefinedLayoutView extends Div {
}
Excluding Vaadin Flow routes from Hilla layouts with autoLayout = false
is not yet supported. See the related GitHub issue for details and discussions.
Defining a Layout in @Route
This next example renders CompanyComponent
inside MainLayout
by defining the layout for the route:
@Tag("div")
@Route(value = "company", layout = MainLayout.class)
public class CompanyComponent extends Component {
}
When using the @Route("path")
annotation to define a route, the component renders by default in the <body>
tag on the page when there is no @Layout
for RouterLayout
. This is because the element returned by HasElement.getElement()
is attached to the <body>
tag.
Layout Matching Routes
To configure which routes a @Layout
annotated RouterLayout
handles, the prefix of the route’s path can be given for the value.
The example below gives a value of /user
, which would match the routes /user
and /user/info
:
@Layout(value="/user")
The default value is /
, which matches all paths.
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 among the child components.
See Updating Page Title on Navigation for more information on this.
Multiple Parent Layouts
Use the @ParentLayout
annotation to define a parent layout for components in the routing hierarchy. Where necessary, a parent can have its own parent layout.
In the example below, MainLayout
is used for everything, which MenuBar
is reused for views:
public class MainLayout extends Div
implements RouterLayout {
}
@Layout
@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")
public class TutorialView extends Div {
}
@Route(value = "icons")
public class IconsView extends Div {
}
MainLayout
encapsulates MenuBar
, which in turn encapsulates TutorialView
or IconsView
— depending on where the user has navigated.
ParentLayout Route Control
Annotating a parent layout with @RoutePrefix("prefix_to_add")
adds a prefix to its children’s route.
In the example here, PathComponent
receives the some
prefix from its parent, resulting in some/path
as its final 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
A child component can bypass the parent’s route prefix by adding absolute = true
to its own @Route
or @RoutePrefix
annotations.
This generic example builds 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
, the result is only content
because it has been defined as "absolute".
The example here defines absolute = true
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
, although 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, Tutorials
with route ""
would be mapped as framework/
.
7A96749F-CD19-4422-A2A2-B4ACD719C9FA