This is a simple web component router that hooks into both the history API and the web components API. You can use this to setup routing for your web components application.
Features:
- Dynamic imports (Lazy loading for javascript modules)
- Simple setup
- Flexibility using either the
render
method or acomponent
name for rendering a route
Documentation:
Installation
npm install simple-wc-router --save
yarn add simple-wc-router
Usage
You can import the Router and/or RouteMixin from the package and use it to extends the web component class
import { Router, RouteMixin } from 'simple-wc-router';
class SomeComponent extends Router(SomeWebComponentLibrary) {
To make sure the routing works as intended, please add a base tag to your root HTML page, like so:
<base href="/">
The base href itself does not have to be /
.
The Router is a class mixin which you can use to extend your webcomponent. The following example will show you how to use it.
As of version 2.1.0 a render method is added to the route definitions.
As of version 2.3.0 you can have optional path parts.
You can make use of dynamic imports if your build tooling supports it. If not make sure the components have been (imported and) defined. The imported component will be passed a routeProps
object containing the properties that are set in the route.
You can define paths as:
Type | Syntax | Explanation |
---|---|---|
Normal | /stocks/latest |
This route can only be exactly matched. |
Dynamic | /stocks/:type |
This route contains the variable type, the value will be provided as routeProps to the given component. |
Optional | /stocks/:type/:?period |
The route contains both a variable type and period. Where period is optional. The route will be matched with and without the period route part. |
Wildcard | * |
This is a fallback pattern if no routes are matched. |
app.js
import { LitElement, html } from 'lit-element';
import { Router } from 'simple-wc-router';
import './pages/page_home';
import './components';
const globalProp = "version-1.2.3";
class App extends Router(LitElement) {
static get routes() {
return [
// Root path
{
path: "/",
component: "page-home"
},
// Using 'type' and 'day' variable.
{
path: "/stock/:type/:day",
component: "page-stocks",
import: () => import("./src/page_stock.js")
},
// Using 'stockId' and optionally 'againstRate' variable.
{
path: "/trade/:stockId/:?againstRate",
component: "page-trade",
import: () => import("./src/page_trade.js")
},
// Using 'category' variable.
{
path: "/news/:category",
render: routeProps => html`
<page-news
.category=${routeProps.category}
.someOtherGlobalProp=${globalProp}>
</page-news>`,
import: () => import("./src/page_news.js")
},
// Fallback for all unmatched routes.
{
path: "*",
render: () => html`<h2>404 The requested page could not be found</h2>`
}
];
}
render() {
return html`
<app-header>
<h1 slot="left">... some title goes here ...</h1>
<nav slot="right">... some navigation goes here ...</nav>
</app-header>
<main>
${this.routeElement}
</main>
<app-footer>
... some copyright goes here ...
</app-footer>
`
}
}
customElements.define('my-app', App);
page_stocks.js
import { LitElement, html } from 'lit-element';
class Stocks extends LitElement {
render() {
// If provided, the properties for type and day are taking from the path.
const { type = 'NASDAC', day = 'monday' } = this.routeProps;
return html`This is the page for ${type} on a ${day}`
}
}
customElements.define('page-stocks', Stocks);
The RouteMixin class should be used for those components that trigger navigation. The navigate
method is added to the class, which only requires you to set a route
property. The navigate
method can also be called with a route. The mixin also provides you a boolean that tells you if the given route is active (isRouteActive
) which you can utilize for e.g. styles.
import { LitElement, html, css } from 'lit-element';
import { RouteMixin } from 'simple-wc-router';
class Button extends RouteMixin(LitElement) {
static get properties() {
return {
route: String,
disabled: Boolean
}
}
static get styles() {
return css`
:host > button.active {
color: red;
}
`;
}
handleClick() {
if (this.disabled) this.navigate('/button-was-disabled-why-did-you-click-it');
this.navigate();
}
render() {
const activeClass = this.isRouteActive ? 'active' : '';
const clickHandler = this.handleClick.bind(this);
return html`
<button class="${activeClass}" @click="${clickHandler}">
<slot></slot>
</button>
`;
}
}
customElements.define('w-button', Button);
Now when you want to use the component, it is as simple as:
<w-button route="/foo/bar">The only bar in town... FooBar</w-button>
Version | Changes |
---|---|
1.0.0 | Initial version of simple web component router |
1.0.1 | Small bugfix |
1.0.2 | Another small bugfix |
1.1.0 | Changed the routing setup |
2.0.0 | Changed route matching, routes must be defined as static. Also created example to play around. |
2.1.0 | Added a render method to the route definition. |
2.2.0 | Added wildcard posibility. |
2.2.1 | Changed the documentation. |
2.3.0 | Added optional routing based on the suggestion JaySunSyn |
2.3.1 | Fixed NPM audit finding |
2.3.2 | Improved documentation |
2.3.3 | Improved documentation |
2.3.4 | Improved build size |