Docs

Documentation versions (currently viewingVaadin 24)

Route Templates Flow

Learn how to use route templates in Flow.

In this guide, you’ll learn how to create a view that accepts multiple route parameters using route templates. You’ll also learn how to use modifiers and regular expressions to tweak the behavior of the route parameters. Finally, a mini-tutorial will help you apply these concepts in a real Vaadin application.

Tip
Using a single route parameter is easier than using a route template. If you can get the job done using the HasUrlParameter<T> interface, use that instead.

Specifying Multiple Route Parameters

To specify multiple route parameters, you use a route template instead of a static path when declaring a @Route. In a route template, one or more of the URL segments is a route parameter. Route parameters must follow the following syntax:

:parameter_name[modifier][(regex)]

The following sections explain this syntax in detail.

The following example demonstrates a view with two route parameters: customerId and action:

@Route("customer/:customerId/:action")
public class CustomerView extends Main {
    ...
}

Now, if you navigate to /customer/cu12345/edit, the router renders the CustomerView with the following route parameter values:

  • customerId"cu12345"

  • action"edit"

Accessing Route Parameter Values

To access the route parameter values, your view must implement the BeforeEnterObserver interface. This interface defines the beforeEnter() method, which is called by the router before navigating to the view. Inside the method, you can access the route parameters:

@Route("customer/:customerId/:action")
public class CustomerView extends Main implements BeforeEnterObserver {

    private static final String PARAM_CUSTOMER_ID = "customerId"; 1
    private static final String PARAM_ACTION = "action";

    @Override
    public void beforeEnter(BeforeEnterEvent event) {
        var customerId = event.getRouteParameters().get(PARAM_CUSTOMER_ID).get();
        var action = event.getRouteParameters().get(PARAM_ACTION).get();
        // Process the parameters
    }
    ...
}
  1. Tip: To improve readability and maintainability, declare route parameter names as constants near the @Route annotation.

The RouteParameters class defines methods for accessing route parameter values as String, Integer, or Long. They all return an Optional<T>.

In the example above, both customerId and tab are required, so you can assume that those route parameter values are never empty. If you try to navigate to /customer or /customer/cu12345, the router returns a 404 Not Found error.

Optional Route Parameters

By default, all route parameters are required. To make a route parameter optional, use the ? modifier:

@Route("customer/:customerId/:action?") 1
public class CustomerView extends Main implements BeforeEnterObserver {

    private static final String PARAM_CUSTOMER_ID = "customerId";
    private static final String PARAM_ACTION = "action";

    @Override
    public void beforeEnter(BeforeEnterEvent event) {
        var customerId = event.getRouteParameters().get(PARAM_CUSTOMER_ID).get();
        var action = event.getRouteParameters().get(PARAM_ACTION).orElse(null); 2
        // Process the parameters
    }
    ...
}
  1. The action route parameter is now optional.

  2. The route parameter value can now be empty.

Now, if you navigate to /customer/cu12345, the action route parameter is empty. You can handle empty parameters by providing a default value, redirecting users, or displaying an error message.

When using multiple optional route parameters, values are assigned from left to right. If a parameter is missing, the next available value shifts left to fill its place. For instance, consider an application with the route customer/:customerId?/:action?:

  • /customer → Calls the customer route with no route parameters at all.

  • /customer/cu12345 → Calls the customer route with "cu12345" as the value of customerId.

  • /customer/cu12345/edit → Calls the customer route with "cu12345" as the value of customerId, and "edit" as the value of action.

Wildcard Route Parameters

By default, a route parameter captures only a single URL segment. However, the last segment in the route template can be declared a wildcard route parameter. This means that the route parameter captures all the segments in its place. A wildcard route parameter is always optional.

To denote a route parameter a wildcard, use the * modifier:

@Route("api/:path*")
public class ApiViewer extends Main implements BeforeEnterObserver {

    @Override
    public void beforeEnter(BeforeEnterEvent event) {
        var path = event.getRouteParameters().get("path").orElse("");
        // Process the path
    }
}

Now, if you navigate to api/com/vaadin/flow/, the path route parameter has the value "com/vaadin/flow".

You can also access the URL segments captured by a wildcard route parameter individually:

@Route("api/:path*")
public class ApiViewer extends Main implements BeforeEnterObserver {

    @Override
    public void beforeEnter(BeforeEnterEvent event) {
        List<String> segments = event.getRouteParameters().getWildcard("path");
        // Process the segments
    }
}

Now, if you navigate to the same URL, the segments variable contains the list ["com", "vaadin", "flow"].

Note
If a route parameter is missing, getWildcard() returns an empty list.

Constraining Route Parameter Values with Regular Expressions

In all the examples discussed, the route parameters accept any value. However, a specific value is often expected for a route parameter and the view should be shown only when that specific value is present in the URL. You can do this by defining a regular expression for the route parameter. This reduces the need for validation and sanitation of route parameter values in the beforeEnter() method.

Note
The syntax of the regular expressions is checked at application startup. If there is an error, the application fails to start.

In the following example, the customerId route parameter is constrained to an integer between 1 and 9 digits, and the action route parameter can be either "view", "edit", or empty:

@Route("customer/:customerId([0-9]{1,9})/:action?(view|edit)")
public class CustomerView extends Main {
    ...
}

If you navigate to a URL that doesn’t meet these constraints, you’ll receive a 404 Not Found error.

When you specify constraints on wildcard route parameters, the regular expression is applied to every segment that would be captured by the route parameter. If any of the segments fails to match the expression, the whole route template fails to match the URL, and you’ll get a 404 Not Found error.

Try It

In this mini-tutorial, you’ll create a view that uses a route template. You’ll then change the route template and see how the view behaves.

Set Up the Project

First, generate a walking skeleton with a Flow UI, open it in your IDE, and run it with hotswap enabled.

Create the View

Create a new package [application package].tutorial.ui.view. Then, in this package, create a new class called TemplateView:

import com.vaadin.flow.component.html.Main;
import com.vaadin.flow.router.BeforeEnterEvent;
import com.vaadin.flow.router.BeforeEnterObserver;
import com.vaadin.flow.router.Route;

@Route("template")
public class TemplateView extends Main implements BeforeEnterObserver {

    private static final String PARAM1 = "param1";
    private static final String PARAM2 = "param2";
    private static final String PARAM3 = "param3";

    @Override
    public void beforeEnter(BeforeEnterEvent event) {
        var param1 = event.getRouteParameters().get(PARAM1).orElse("N/A");
        var param2 = event.getRouteParameters().get(PARAM2).orElse("N/A");
        var param3 = event.getRouteParameters().get(PARAM3).orElse("N/A");
        setText("param1: \"" + param1 + "\", param2: \"" + param2
            + "\", param3: \"" + param3 + "\"");
    }
}

Open your browser and go to: http://localhost:8080/template

You should see:

param1: "N/A", param2: "N/A", param3: "N/A"
Define Required Route Parameters

Next, introduce the three route parameters, like this:

@Route("template/:param1/:param2/:param3")
public class TemplateView extends Main implements BeforeEnterObserver {
    ...
}

Now, go back to your browser. Because the route parameters are required and you haven’t provided any values, you should see a Could not navigate to 'template' error message.

To give values for the route parameters, navigate to this URL:

You should see:

param1: "say", param2: "hello", param3: "vaadin"
Make Route Parameters Optional

You’re now going to make the first two route parameters optional. Add the ? modifier to them:

@Route("template/:param1?/:param2?/:param3")
public class TemplateView extends Main implements BeforeEnterObserver {
    ...
}

Go back to your browser. You should still see all three route parameter values. However, watch what happens if you go to:

Since the first two parameters are optional, the last parameter takes the first available value. You should see:

param1: "N/A", param2: "N/A", param3: "say"

Now add a second route parameter value by navigating to:

You should see:

param1: "say", param2: "N/A", param3: "hello"
Mark a Route Parameter as Wildcard

You’re now going to make the last route parameter a wildcard. Add the * modifier to it:

@Route("template/:param1?/:param2?/:param3*")
public class TemplateView extends Main implements BeforeEnterObserver {
    ...
}

Go back to the browser. If you reload the page, you should now see the following:

param1: "say", param2: "hello", param3: "N/A"

The "hello" string has moved from param3 to param2. The reason for this is that wildcard route parameters are also optional. Next, navigate to the following URL:

The last route parameter now holds two segments instead of one. You should see:

param1: "say", param2: "hello", param3: "to/vaadin"
Add Regular Expressions

You’re now going to add some regular expressions to constrain the route parameters. You’ll force param1 to consist of digits only, and all the segments of param3 to be one of hello, to, and vaadin:

@Route("template/:param1?([0-9]*)/:param2?/:param3*(hello|to|vaadin)")
public class TemplateView extends Main implements BeforeEnterObserver {
    ...
}

Go back to the browser. You should now see a Could not navigate to 'template/say/hello/to/vaadin. This is because the first route parameter value is not a number. To fix this, navigate to:

You should see:

param1: "123", param2: "say", param3: "hello/to/vaadin"
Final Thoughts

You’ve now successfully implemented route templates in Flow. You learned how to:

  • Specify multiple route parameters in a view.

  • Make route parameters optional.

  • Use a wildcard route parameter to capture multiple URL segments.

  • Use regular expressions to constrain the values of route parameters.

You’re now ready to use route parameters in real Vaadin applications. Try specifying your own route template, and make a custom API for navigating to it! Include at least one numeric route parameter, and use RouteParameters.getInteger() to retrieve it.