Routing and Navigation

TypeScript routes, typically for views or sub-views, are defined in a Router instance in the index.ts script. If you also have server-side views defined in Java, you need to configure the router to fall back to those.

A typical router configuration that supports both TypeScript and Java routes goes as follows:

import { Router } from '@vaadin/router';
import { Flow } from '@vaadin/flow-frontend';

// Get the server-side routes from imports generated in the server
const {serverSideRoutes} = new Flow({
  imports: () => import('../target/frontend/generated-flow-imports')
});

export const router = new Router(document.querySelector('#outlet'));
router.setRoutes([
  // A single route here
  {
    path: 'users',            // The route
  	component: 'users-view',  // The component handling the route
    // Import the view component when needed
  	action: async () => { await import ('./views/users/users-view'); },
  },
  // For server-side, the next magic line sends all unmatched routes:
  ...serverSideRoutes // IMPORTANT: this must be the last entry in the array
]);

Client-side routes are explicitly listed in the configuration, and server-side routes are added there through the serverSideRoutes variable.

In the example above, we have a single client-side route users, which maps to a users-view component. It would be defined in a file views/users/users-view.ts under the frontend folder where the index.ts is located.

In the following sections, we break up the client-side and server-side routing.

Pure Client Side Routing

In a pure TypeScript application with no server-side Java routes, you can configure routing as follows:

import { Router } from '@vaadin/router';

export const router = new Router(document.querySelector('#outlet'));
router.setRoutes([
  // A single route here
  {
    path: 'users',            // The route
  	component: 'users-view',  // The component handling the route
    // Import the view component when needed
  	action: async () => { await import ('./views/users/users-view'); },
  }
]);

Connecting With Server Side Routing

In the example earlier, we defined connecting with server-side routes defined in Java. This allows combining client-side views created in TypeScript with server-side views created in Java using the @Route annotation. Routing in Java views is described in Defining Routes [in Java].

The glue for mixing views is the @vaadin/flow-frontend module which allows lazy initialization of Flow and navigation to server views.

The server-side Java Component API (Flow) in Vaadin provides a client module that acts as a bridge between a client router and server routes. It is also possible to integrate server-side Vaadin with any JavaScript-based routing solution.

The Flow client is distributed as a part of the com.vaadin:vaadin Maven artifact. It is automatically included into any Vaadin application and can be imported into any TypeScript file as import { Flow } from '@vaadin/flow-frontend';.

Using the Client

First, you have to import the module, and then you have to create the Flow instance.

At this point, it is needed to specify the location to the Flow generated file with the imports for Java views, typically /target/frontend/generated-flow-imports.js in a Vaadin Maven project.

Notice that the import() function should be used to lazy load Flow dependencies the first time the user navigates to a server-side view.

import { Flow } from '@vaadin/flow-frontend';
const flow = new Flow({
  imports: () => import('../target/frontend/generated-flow-imports')
});

Finally, make Vaadin Router pass all unmatched paths to Flow server by adding …​serverSideRoutes at the end of the router configuration block:

import { Router } from '@vaadin/router';
import { Flow } from '@vaadin/flow-frontend';

const {serverSideRoutes} = new Flow({
  imports: () => import('../target/frontend/generated-flow-imports')
});

export const router = new Router(document.querySelector('#outlet'));
router.setRoutes([
  {
    path: 'categories',
    component: 'app-categories',
    action: async () => { await import('./views/app-categories-view'); }
  },
  // for server-side, the next magic line sends all unmatched routes:
  ...serverSideRoutes // IMPORTANT: this must be the last entry in the array
]);