Introduction to Routing Using Stencil

@stencil/router is the NPM package to use with Stencil to make it easy to define routes for your web component-powered PWA. The API for the router is very similar to React Router’s, so you may already be familiar with the syntax.

In this post we’ll build a simple example where we have global components for an app shell, header and menu, as well as 3 routes: home, about and contact.

Setup & Configuration

First, make sure you have the @stencil/router package installed in your project:

$ npm install @stencil/router

# or, using Yarn
$ yarn add @stencil/router

Next you’ll want to make sure that your Stencil config file’s config object contains a collections array with the router package:

stencil.config.js

exports.config = {
  bundles: [
    { components: ['app-shell', 'app-header', 'app-menu'] }
  ],
  collections: [
    { name: '@stencil/router' }
  ]
};

// ...

If you're using Stencil's starter app to initiate your project, the @stencil/router package and proper config will already be in place.

Defining Routes

Routes are defined in a global <stencil-router> element that contains <stencil-route> elements for each individual route definition. Routes will be rendered inside the stencil-router element.

The <stencil-router> should have an id that the <stencil-route> elements can refer to. Here’s a simple example with our 3 routes:

<stencil-router id="router">
  <stencil-route
    url="/"
    component="app-home"
    router="#router"
    exact={true}
  />
  <stencil-route
    url="/contact"
    component="app-contact"
    router="#router"
  />
  <stencil-route
    url="/about"
    component="app-about"
    router="#router"
  />
</stencil-router>

Notice the use of exact={true} on the root / url to match only the root path to the home component.

We would place such route config in our app’s top level component, here app-shell. Here, our whole app root component could look like this:

/components/app-shell/app-shell.tsx

import { Component } from '@stencil/core';

@Component({
  tag: 'app-shell'
})
export class AppComponent {
  render() {
    return [
      <app-header title="Fancy Alligator!" />,

      <app-menu />,

      <stencil-router id="router">
        <stencil-route
          url="/"
          component="app-home"
          router="#router"
          exact={true}
        />
        <stencil-route
          url="/contact"
          component="app-contact"
          router="#router"
        />
        <stencil-route
          url="/about"
          component="app-about"
          router="#router"
        />
      </stencil-router>
    ];
  }
}

The render method returns multiple top level elements. This can be done using an array of top level elements, like in the above example. Or, it can also be done by wrapping the 3 top level elements in a wrapping div element.

Linking to a Route

To link to a route with the app, use the <stencil-route-link> element with the id of the router and the url. Here for example, here’s the render method of our app-menu component:

/components/app-menu/app-menu.tsx (partial)

render() {
  return (
    <ul>
      <li>
        <stencil-route-link
          router="#router"
          url="/"
          activeClass="active"
          exact={true}
        >
          Home
        </stencil-route-link>
      </li>
      <li>
        <stencil-route-link
          router="#router"
          url="/about"
          activeClass="active"
        >
          About
        </stencil-route-link>
      </li>
      <li>
        <stencil-route-link
          router="#router"
          url="/contact"
          activeClass="active"
        >
          Contact
        </stencil-route-link>
      </li>
    </ul>
  );
}

Here we’re also using the activeClass property to set a class name on active routes. The root route also has its exact property set to true so that the active class gets added only on an exact match of the url.

Passing Data to a Route

You can also pass props to a route in its configuration using the componentProps property:

<stencil-route
  url="/contact"
  component="app-contact"
  router="#router"
  componentProps={{ method: 'Walkie-talkie' }}
/>

And then in the component it can be accessed using using the @Prop decorator:

app-contact.tsx

import { Component, Prop } from '@stencil/core';

@Component({
  tag: 'app-contact'
})
export class ContactComponent {
  @Prop() method: string;
  render() {
    return <p>📞 Getting in touch by {this.method}</p>;
  }
}

👷‍ The Stencil router is in heavy development and the API is bound to change rapidly. Refer to the official repo for the latest changes.

  Tweet It
✖ Clear

🕵 Search Results

🔎 Searching...