This project is part of the @thi.ng/umbrella monorepo.
Generic router for browser & non-browser based applications.
- Declarative route definitions
- Parametric routes, each param with optional value coercion & validation
- Route authentication handler to enable/disable routes based on other state factors
- Fallback route
- Enforced initial route (optional)
- Route formatting (with params)
- HTML5 history & hash fragment support
Partially based on the Clojure implementation in thi.ng/domus.
STABLE - used in production
Search or submit any issues for this package
- @thi.ng/hdom - Lightweight vanilla ES6 UI component trees with customizable branch-local behaviors
- @thi.ng/rdom - Lightweight, reactive, VDOM-less UI/DOM components with async lifecycle and @thi.ng/hiccup compatible
yarn add @thi.ng/router
ES module import:
<script type="module" src="https://cdn.skypack.dev/@thi.ng/router"></script>
For Node.js REPL:
const router = await import("@thi.ng/router");
Package sizes (brotli'd, pre-treeshake): ESM: 1.38 KB
Several demos in this repo's /examples directory are using this package.
A selection:
Screenshot | Description | Live demo | Source |
---|---|---|---|
Complete mini SPA app w/ router & async content loading | Demo | Source |
import { HTMLRouter, EVENT_ROUTE_CHANGED } from "@thi.ng/router";
// router configuration
const config = {
// use hash fragment for routes
useFragment: true,
// fallback route (when no other matches)
defaultRouteID: "home",
// optional enforced route when router starts
initialRouteID: "home",
// Optional route path component separator. Default: `/`
separator: "/",
// Route prefix. Default: `/` (or `#/` if `useFragment` is enabled).
// All routes to be parsed by `route()` are assumed to have this prefix.
// All routes returned by `format()` will include this prefix.
prefix: "#/",
// actual route defs
// these are checked in given order
// IMPORTANT: rules with common prefixes MUST be specified in
// order of highest precision / longest path
routes: [
{
// each route MUST have an ID
id: "home",
// optional title for UI purposes (no internal function)
title: "Home page",
// this array defines the route path items
match: ["home"]
},
{
id: "user-profile",
// this rule is parametric
// variable items are prefixed with `?`
match: ["users", "?id"],
// coercion & validation handlers for "?id" param
// coercion fn is applied BEFORE validator
validate: {
id: {
coerce: (x) => parseInt(x),
check: (x)=> x > 0 && x < 100
}
}
},
{
id: "image",
// this route has 2 params and matches (for example):
// "/images/07a9d87b-c07a-42e3-82cf-baea2f94facc/xl"
match: ["images", "?id", "?size"],
validate: {
id: {
check: (x)=> isUUID(x)
},
size: {
check: (x)=> /^(s|m|l|xl)$/.test(x)
}
},
// enable auth for this route
// (see info about authenticator functions below)
auth: true
},
{
id: "group-list",
// matches only: "/users" or "/images"
match: ["?type"],
validate: {
type: {
check: (x) => /^(users|images)$/.test(x)
}
},
auth: true
},
]
};
// `HTMLRouter` ONLY works in browser environments
// for non-browser use cases use `BasicRouter`
const router = new HTMLRouter(config);
router.addListener(EVENT_ROUTE_CHANGED, console.log);
router.start();
If this project contributes to an academic publication, please cite it as:
@misc{thing-router,
title = "@thi.ng/router",
author = "Karsten Schmidt",
note = "https://thi.ng/router",
year = 2014
}
© 2014 - 2023 Karsten Schmidt // Apache License 2.0