Getting Started

Learn how to work with the @aurelia/router package to implement routing in your Aurelia applications.

Routing with Aurelia feels like a natural part of the framework. It can easily be implemented into your applications in a way that feels familiar if you have worked with other frameworks and library routers.

This section is broken up into two parts—a quick introduction to the router and router configuration.

If you are looking for details on configuring the router (set titles, handle unknown routes, etc.), please see the Configuration section at the end of this guide.

Currently, two routers ship with Aurelia: router lite and core router. This section refers to the core router package that lives in @aurelia/router — please see the warning note below on a caveat some developers encounter when working with the router.

Before you go any further: Please ensure you are importing from the @aurelia/router package. Sometimes import extensions will autocomplete your imports and import from the aurelia package, which currently exports the lite router. Eventually, the aurelia package will export the @aurelia/router package, but it currently does not. We have noticed, in many instances, that using the incorrect router imports is why routing is not working.

A quick introduction to routing

See how you can configure and implement routing in your Aurelia applications in only a few minutes. Of course, you will want to expand upon this as you build your routes. Here we only learn the bare minimum to get started.

The following getting started guide assumes you have an Aurelia application already created. If not, consult our Quick Start to get Aurelia installed in minutes.

Register the router and create routes

To use the router, we have to register it with Aurelia. We do this inside of main.ts (or main.js if you're working with Javascript) — the router is then enabled after it is registered. You might already have code like this if you chose the routing example when generating using the Makes scaffolding tool.

main.ts
import Aurelia from 'aurelia';

// Our router configuration import to register the Router with Aurelia's DI
import { RouterConfiguration } from '@aurelia/router';

import { MyApp } from './my-app';

Aurelia
  .register(RouterConfiguration)
  .app(MyApp)
  .start();

Once again, it bears repeating. Please make sure your router imports are being imported from @aurelia/router in your `main.ts` file, but also in other parts of your Aurelia application as well.

Now, we create our routes. We'll do this inside my-app.ts and use the static routes property. Please note that there is also a @routes decorator, which is detailed inside the Creating Routes section.

my-app.ts
import { HomePage } from './home-page';

export class MyApp {
    static routes = [
        {
            path: '',
            component: HomePage,
            title: 'Home'
        },
    ];
}

For our two routes, we import and provide their respective components. Your components are just classes and can be very simple. Here is the HomePage component. Please note that you can use inline imports when creating routes, also detailed in the Creating Routes section.

Take note of the path property which is empty. This tells the router that the HomePage component is our default route. If no route is supplied, it will load this as the default component. The component property is the component that will be loaded (self-explanatory). And the title property is the title for our route.

home-page.html
<h1>Homepage</h1>
<p>This is the homepage.</p>

And the view model for our component is equally simple:

home-page.ts
export class HomePage {
}

Create the HTML View

First, let's look at the HTML. If you use the makes tool to scaffold your Aurelia application. This might be my-app.html

my-app.html
<!-- Two routes using the load attribute containing the path of the route -->
<a load="/">Home</a>

<!-- This is where our routed components are loaded -->
<au-viewport></au-viewport>

load

Notice how we use a standard hyperlink <a> tags, but they have an load attribute instead of href? This attribute tells the router that these are routable links. The router will translate these load values into routes (either path or route name). By default, the router does also allow you to use href for routes (a setting that can be turned off below configuring useHref).

au-viewport

This tells the router where to display your components. It can go anywhere inside your HTML. It can also have a name (handy for instances where there are multiple au-viewport elements), and you can have more than one.

Configuration

The router allows you to configure how it interprets and handles routing in your Aurelia applications. The customize method on the RouterConfiguration object can be used to set numerous router settings besides the useUrlFragmentHash value.

Can't find what you're looking for in this section? We have a Router Recipes section detailing many tasks for working with the router, from passing data between routes to route guards.

Setting the title of your application

The title can be set for the overall application. By default, the title uses the following value: ${componentTitles}${appTitleSeparator}Aurelia the component title (taken from the route or component) and the separator, followed by Aurelia.

import Aurelia from 'aurelia';
import { RouterConfiguration } from '@aurelia/router'; 

Aurelia
  .register(
    RouterConfiguration.customize({ 
      title: '${componentTitles}${appTitleSeparator}My App'
    }))
  .app(component)
  .start();

In most instances, using the above string title is what you will want. You will want the solution below if you need to set the title or transform the title programmatically.

Customizing the title

Using the transformTitlemethod from the router customization, the default title-building logic can be overwritten. This allows you to set the title programmatically, perform translation (using Aurelia i18n or other packages) and more.

Are you trying to set the title using the Aurelia i18n package? Visit the section on configuring translated router titles here.

main.ts
import { RouterConfiguration, RoutingInstruction, Navigation } from '@aurelia/router';
import { Aurelia } from 'aurelia';

import Aurelia from 'aurelia';
import { RouterConfiguration } from '@aurelia/router';
import { MyApp } from './my-app';

Aurelia
  .register(RouterConfiguration.customize({
      title: {
        transformTitle: (title: string, instruction: RoutingInstruction, navigation: Navigation) => {
          return `${title} - MYAPP`;
        }
      }
  })
  .app(MyApp)
  .start();

Changing the router mode (hash and pushState routing)

If you do not provide any configuration value, the default is hash-based routing. This means a hash will be used in the URL. If your application requires SEO-friendly links instead of hash-based routing links, you will want to use pushState.

Configuring pushState routing

We are performing the configuration inside of the main.ts file, which is the default file created when using the Makes CLI tool.

import Aurelia from 'aurelia';
import { RouterConfiguration } from '@aurelia/router'; 

Aurelia
  .register(RouterConfiguration.customize({ useUrlFragmentHash: false }))
  .app(component)
  .start();

By calling the customize method, you can supply a configuration object containing the property useUrlFragmentHash and supplying a boolean value. If you supply true this will enable hash mode. The default is true.

If you are working with pushState routing, you will need a base HREF value in the head of your document. The scaffolded application from the CLI includes this in the index.html file, but if you're starting from scratch or building within an existing application, you need to be aware of this.

<head>
    <base href="/">
</head>

PushState requires server-side support. This configuration is different depending on your server setup. For example, if you are using Webpack DevServer, you'll want to set the devServer historyApiFallback option to true. If you are using ASP.NET Core, you'll want to call routes.MapSpaFallbackRoute in your startup code. See your preferred server technology's documentation for more information on how to allow 404s to be handled on the client with push state.

Configuring route markup parsing using useHref

The useHref configuration setting is something all developers working with routing in Aurelia need to be aware of. By default, the router will allow you to use both href as well as load for specifying routes.

Where this can get you into trouble are external links, mailto links and other types of links that do not route. A simple example looks like this:

<a href="mailto:myemail@gmail.com">Email Me</a>

By default, this seemingly innocent and common scenario will trigger the router and cause an error in the console.

You have two options when it comes to working with external links. You can specify the link as external using the external attribute.

<a href="mailto:myemail@gmail.com" external>Email Me</a>

Or, you can set useHref to false and only ever use the load attribute for routes.

import Aurelia from 'aurelia';
import { RouterConfiguration } from '@aurelia/router'; 

Aurelia
  .register(RouterConfiguration.customize({
      useHref: false
  }))
  .app(component)
  .start();

Handling unknown components

If you are using the router to render components in your application, there might be situations where a component attempts to be rendered that do not exist. This can happen while using direct routing (not configured routing)

This section is not for catch-all/404 routes. If you are using configured routing, you are looking for the section on catch-all routes here.

To add in fallback behavior, we can do this in two ways. The fallback attribute on the <au-viewport> element or in the router customize method (code).

Create the fallback component

Let's create the missing-page component (this is required, or the fallback behavior will not work). First, we'll create the view model for our missing-page component.

missing-page.ts
export class MissingPage {
  public static parameters = ['id'];
  public missingComponent: string;

  public loading(parameters: {id: string}): void {
    this.missingComponent = parameters.id;
  }
}

For the fallback component, an ID gets passed as a parameter which is the value from the URL. If you were to attempt to visit a non-existent route called "ROB," the missingComponent value would be ROB.

Now, the HTML.

missing-page.html
<h3>Ouch! I couldn't find '${missingComponent}'!</h3>

Programmatically

By using the fallback property on the customize method when we register the router, we can pass a component.

import Aurelia from 'aurelia';
import { RouterConfiguration } from '@aurelia/router';
import { MyApp } from './my-app';
import { MissingPage } from './missing-page'; 

Aurelia
  .register(RouterConfiguration.customize({
    fallback: MissingPage,
  }))
  .app(MyApp)
  .start();

Attribute

Sometimes the fallback attribute can be the preferred approach to registering a fallback. Import your fallback component and pass the name to the fallback attribute. The same result, but it doesn't require touching the router registration.

my-app.html
<import from="./missing-page"></import>

<au-viewport fallback="missing-page"></au-viewport>

Configuring the route swap order

The swapStrategy configuration value determines how contents are swapped in a viewport when transitioning. Sometimes, you might want to change this depending on the type of data you are working with or how your routes are loaded. A good example of configuring the swap order is when you're working with animations.

  • attach-next-detach-current (default)

  • attach-detach-simultaneously

  • detach-current-attach-next

  • detach-attach-simultaneously

Still, confused or need an example? You can find an example application with routing over on GitHub here.

Last updated