Navigate to a View
In this guide, you’ll learn how to use RouterLink
and UI.navigate()
to navigate between views. You’ll also learn how to improve the readability of your code by encapsulating some of the navigation logic into your own API. At the end, a mini-tutorial helps you to apply these concepts in a real Vaadin application.
Router Links
RouterLink
is a component that creates a clickable link for navigation. In HTML, it corresponds to an anchor (<a>
) element.
Tip
| Links are preferable to programmatic navigation because they improve accessibility. They also allow users to open links in new browser tabs. |
The following example creates a link to the MainView
:
var link = new RouterLink("Home", MainView.class);
myLayout.add(link);
If the view is accepting a single route parameter, you can pass the parameter value to the RouterLink
constructor.
In the following example, CustomerDetailsView
implements the HasUrlParameter<T>
interface and takes a single string parameter - the customer’s ID. The link navigates to the details of the customer with ID "cu1234"
:
var link = new RouterLink("Customer Details", CustomerDetailsView.class, "cu1234");
myLayout.add(link);
If the view is accepting multiple route parameters, you need to construct an instance of RouteParameters
and pass it to the RouterLink
constructor. You can construct it in different ways; see its API documentation for details.
The following example creates a link to the customer details view with two route parameters; customerId
with the value of "cu1234"
, and mode
with the value of "edit"
:
var link = new RouterLink("Edit Customer", CustomerDetailsView.class,
new RouteParameters(Map.of("customerId", "cu1234", "mode", "edit")));
myLayout.add(link);
For more information about route parameters, see the Route Parameters guide.
Programmatic Navigation
Using links is not the only way to navigate from a view to another. You can trigger a navigation in Java by calling any of the UI.navigate()
methods. You typically do this in response to user actions, such as inside button click listeners, but this is not a requirement. You could also trigger navigation from a background thread using server push, for instance.
The API of UI.navigate()
is similar to that of RouterLink
. In the following example, the router attempts to navigate to the home view when the user clicks the button:
var button = new Button("Home");
button.addClickListener(event ->
UI.getCurrent().navigate(MainView.class)
);
If the view is accepting a single route parameter, you can pass the parameter value to UI.navigate()
, like this:
var button = new Button("Customer Details");
button.addClickListener(event ->
UI.getCurrent().navigate(CustomerDetailsView.class, "cu1234")
);
If the view is accepting multiple route parameters, you need to construct an instance of RouteParameters
and pass it to UI.navigate()
, like this:
var button = new Button("Edit Customer");
button.addClickListener(event ->
UI.getCurrent().navigate(CustomerDetailsView.class,
new RouteParameters(Map.of("customerId", "cu1234", "mode", "edit"))
)
);
Your Own API
Instead of scattering UI.navigate()
calls throughout your codebase, it’s a good practice to encapsulate navigation logic within dedicated methods. This makes the code more readable, maintainable, and easier to refactor.
In the following example, the CustomerDetailsView
has a static method for navigating to the details of the customer with the given ID:
@Route("customer")
public class CustomerDetailsView extends Main implements HasUrlParameter<String> {
public static void showCustomerDetails(String customerId) {
UI.getCurrent().navigate(CustomerDetailsView.class, customerId);
}
...
}
When you want to navigate to the view, you call the method, like this:
var button = new Button("Customer Details");
button.addClickListener(event ->
CustomerDetailsView.showCustomerDetails("cu1234")
);
If you use multiple route parameters, or custom parameter types, this approach becomes even more useful.
In the following example, the CustomerDetailsView
accepts two route parameters; a value object CustomerId
and an enum Mode
:
@Route("customer/:customerId/:mode?(edit|view)") 1
public class CustomerDetailsView extends Main implements HasUrlParameter<String> {
public enum Mode {
edit, view
}
private static RouteParameters createRouteParameters(
CustomerId customerId, Mode mode) {
return new RouteParameters(
Map.of(
"customerId", customerId.toString(),
"mode", mode.toString()
)
);
}
public static RouterLink createEditLinkTo(String text, CustomerId customerId) {
return new RouterLink(text, CustomerDetailsView.class,
createRouteParameters(customerId, Mode.edit));
}
public static void editCustomerDetails(CustomerId customerId) {
UI.getCurrent().navigate(CustomerDetailsView.class,
createRouteParameters(customerId, Mode.edit));
}
...
}
-
This is a route template with two route parameters.
With an API like this, you can create a new router link like this:
CustomerId customerId = ...;
myLayout.add(CustomerDetailsView.createEditLinkTo("Edit Customer", customerId));
If you want to programmatically navigate to the view, you can do it like this:
CustomerId customerId = ...;
var button = new Button("Edit Customer");
button.addClickListener(event ->
CustomerDetailsView.editCustomerDetails(customerId)
);
React Views
So far, all the examples have covered navigating from one Flow view to another. However, you can also navigate from a Flow view to a React view. Unlike Flow views, which use Java class references for navigation, React views require string-based routes because they don’t have a corresponding Java class.
You can use anchor elements for navigation, or trigger programmatic navigation using UI.navigate()
.
In Flow, you create anchors like this:
var link = new Anchor("path/to/react/view", "Link to React View");
myLayout.add(link);
Note
|
Vaadin sets the base URL of the application to the path of the root view. All relative links are resolved against this URL. This means that you don’t have to worry about the context path when you create Anchor objects.
|
You can also programmatically navigate to React views, like this:
var button = new Button("Go to React view");
button.addClickListener(event -> UI.getCurrent().navigate("path/to/react/view"));
Try It
In this mini-tutorial, you’ll learn how to navigate between Flow views using both links and programmatic navigation. Route parameters are not covered here, as they have their own dedicated guides.
Set Up the Project
First, generate a walking skeleton with a Flow UI, open it in your IDE, and run it with hotswap enabled.
Note
| If you completed the mini-tutorial on adding views, you can continue using the same project. |
Modify the Todo View
Open TodoView
and update its route to manage/tasks/with/vaadin
. If you followed the adding views tutorial, you’ve already done this.
@Route("manage/tasks/with/vaadin")
@PageTitle("Task List")
@Menu(order = 0, icon = "vaadin:clipboard-check", title = "Task List")
public class TodoView extends Main {
...
}
Create the Links View
Now, you’ll create a new view that provides multiple ways to navigate to the todo view. Create a new package [application package].tutorial.ui.view
package, and in it a class called LinksView
:
import com.vaadin.flow.component.html.Main;
import com.vaadin.flow.router.Route;
@Route("links")
public class LinksView extends Main {
public LinksView() {
}
}
Add a Router Link
A RouterLink
creates a clickable link to another view. Modify LinksView
to include a link to the TodoView
:
import com.vaadin.flow.component.html.Main;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.router.RouterLink;
@Route("links")
public class LinksView extends Main {
public LinksView() {
add(new RouterLink("Todo", TodoView.class));
}
}
Now, open your browser and go to: http://localhost:8080/links
Hover on the "Todo" link to see that it points to http://localhost:8080/manage/tasks/with/vaadin
. Click the link to navigate to the todo view, then use the browser’s back button to return.
Navigate Programmatically
Next, you’ll add a button that navigates to the todo view when clicked. Modify LinksView
to include a Button
:
import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.html.Main;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.router.RouterLink;
@Route("links")
public class LinksView extends Main {
public LinksView() {
add(new RouterLink("Todo", TodoView.class));
add(new Button("Todo",
event -> UI.getCurrent().navigate(TodoView.class)));
}
}
Switch back to the browser. Thanks to hotswap, the new Todo button should appear automatically. Click it to navigate to the todo view.
Create an API
To make navigation more reusable and readable, you’ll now create a dedicated method for navigating to the todo view.
Open TodoView
and add this method:
@Route("manage/tasks/with/vaadin")
@PageTitle("Task List")
@Menu(order = 0, icon = "vaadin:clipboard-check", title = "Task List")
public class TodoView extends Main {
...
public static void showTodos() {
UI.getCurrent().navigate(TodoView.class);
}
}
Now, update LinksView
to use this method instead of calling UI.getCurrent().navigate()
directly:
@Route("links")
public class LinksView extends Main {
public LinksView() {
add(new RouterLink("Todo", TodoView.class));
add(new Button("Todo", event -> TodoView.showTodos()));
}
}
Go back to the browser and click the button. It works the same as before, but your code is cleaner and easier to maintain.
Final Thoughts
You’ve now explored different ways to navigate between Flow views. Here’s what you’ve learned:
-
Creating a navigation link using
RouterLink
. -
Programmatically navigating using
UI.navigate()
. -
Building a reusable navigation API, improving code readability.
Now that you know how to navigate between views, check out the Pass Data to a View guide to learn how to pass data to a view while navigating to it.