Defining Routes
A Router maps URL paths, such as /home and /about, to the components rendered for those paths.
The router tracks the current URL and selects the matching components. Retend includes this router, so no additional routing library is required.
Setting Up Routes
An array of Route Records configures application routing. Each record maps a URL path to a component.
The defineRoutes helper creates the array:
import { Router, defineRoutes, createRouterRoot } from 'retend/router'; import { renderToDOM } from 'retend-web'; // 1. Create your page components function Home() { return <div>Welcome to the Home Page</div>; } function About() { return <div>About Us</div>; } // 2. Define your routes const routes = defineRoutes([ { path: '/', component: Home }, { path: '/about', component: About }, ]); // 3. Initialize the Router const router = new Router({ routes }); const root = document.getElementById('app')!; // 4. Render the router to the screen renderToDOM(root, () => createRouterRoot(router));
The createRouterRoot function converts the router into a renderable component.
Nested Routes and Layouts
Applications often share layout elements, such as a header or navigation sidebar, across pages.
Nested Routes let a parent route provide the layout for its child routes. <Outlet /> marks where the child component is rendered.
import { defineRoutes, Outlet } from 'retend/router'; function DashboardLayout() { return ( <div class="dashboard-layout"> <aside>Sidebar Navigation</aside> <main> {/* The child page content will appear here */} <Outlet /> </main> </div> ); } function Overview() { return <h2>Dashboard Overview</h2>; } function Settings() { return <h2>User Settings</h2>; } const routes = defineRoutes([ { path: '/dashboard', component: DashboardLayout, children: [ { path: 'overview', component: Overview }, { path: 'settings', component: Settings }, ], }, ]);
At /dashboard/overview, the router renders DashboardLayout and places Overview at <Outlet />. At /dashboard/settings, the layout remains rendered and the outlet content changes.
Default Child Routes
At /dashboard, <Outlet /> is empty if no child route matches. A default child route is defined with an empty path (''):
const routes = defineRoutes([ { path: '/products', component: ProductsLayout, children: [ { path: '', component: ProductList }, // This loads by default at /products { path: 'categories', component: CategoriesList }, ], }, ]);
Dynamic URLs
Dynamic routes are used when a URL contains variable data, such as a user ID or post title. A path segment is prefixed with a colon (:):
const routes = defineRoutes([ // This matches /users/123, /users/alice, etc. { path: '/users/:userId', component: UserProfile }, // You can even have multiple dynamic segments { path: '/posts/:category/:postId', component: BlogPost }, ]);
The following sections describe how to read values such as userId from components.
Handling "404 Not Found"
A custom "Not Found" page is defined for URLs that do not match another route by using an asterisk (*) as the path.
The router checks routes from top to bottom, so the catch-all route is placed last:
const routes = defineRoutes([ { path: '/', component: Home }, { path: '/about', component: About }, // If nothing above matched, this will run { path: '*', component: NotFoundPage }, ]);
The router can now select a component for each matching URL.