eleva

Router Plugin

Version: 1.1.1 Type: Client-Side Routing Plugin Bundle Size: ~15KB minified Dependencies: Eleva core

The Router Plugin is a powerful, reactive, and fully extensible routing solution for Eleva. It provides client-side navigation with support for multiple routing modes, navigation guards, lazy loading, layouts, and a comprehensive plugin system.


Prerequisites

Before using the Router Plugin, you should be familiar with:


TL;DR - Quick Reference

Minimal Setup

import Eleva from "eleva";
import { Router } from "eleva/plugins";

const app = new Eleva("myApp");
const router = app.use(Router, {
  mode: "hash",
  mount: "#app",
  routes: [
    { path: "/", component: HomePage },
    { path: "/users/:id", component: UserPage },
    { path: "*", component: NotFoundPage }
  ]
});
// Router starts automatically (autoStart: true by default)

⚠️ No Manual Mount Needed

When using the Router plugin, you don’t need to call app.mount(). The router automatically handles mounting components based on the current route.

// ❌ Don't do this when using Router
app.use(Router, { mount: '#app', routes });
app.mount(document.querySelector('#app'), 'HomePage'); // Not needed!

// ✅ Correct - Router handles mounting automatically
app.use(Router, { mount: '#app', routes });
// That's it! Router will mount the matched component (autoStart: true)

Common Operations

// Navigate
await router.navigate("/users/123");
await router.navigate({ path: "/users/:id", params: { id: "123" } });

// Access current route (reactive)
router.currentRoute.value      // Full route info
router.currentParams.value     // { id: "123" }
router.currentQuery.value      // { tab: "settings" }

// Watch for changes
router.currentRoute.watch((route) => console.log(route.path));

// Add guard
const unsub = router.onBeforeEach((to, from) => {
  if (to.meta.requiresAuth && !isLoggedIn()) return "/login";
});

// Stop router (can restart)
await router.stop();

// Destroy router (full cleanup)
await router.destroy();

// Uninstall plugin entirely
await Router.uninstall(app);

Route Definition Cheatsheet

{ path: "/", component: HomePage }                           // Static route
{ path: "/users/:id", component: UserPage }                  // Dynamic param
{ path: "/posts/:category/:slug", component: PostPage }      // Multiple params
{ path: "*", component: NotFoundPage }                       // Catch-all (404)
{ path: "/admin", component: () => import("./Admin.js") }    // Lazy loaded
{ path: "/dashboard", component: Page, layout: Layout }      // With layout
{ path: "/settings", component: Page, meta: { auth: true } } // With metadata

Note: Nested routes (children property) are not supported. Use shared layouts with flat routes instead. See Configuration.

Guard Return Values

| Return | Effect | |——–|——–| | true / undefined | Allow navigation | | false | Block navigation | | "/path" | Redirect to path | | { path, query, ... } | Redirect with options |

Event Quick Reference

| Event | Can Block | Use Case | |——-|———–|———-| | router:beforeEach | Yes | Auth guards, logging | | router:beforeResolve | Yes | Loading indicators | | router:afterResolve | No | Hide loading | | router:beforeRender | No | Page transitions | | router:afterRender | No | Animations | | router:scroll | No | Scroll restoration | | router:afterEach | No | Analytics | | router:error | No | Error reporting |

No router:notFound Event: When no route matches and no * route exists, the router emits router:error. Define a catch-all route ({ path: "*", component: NotFoundPage }) for 404 handling.

Template Context: Use ${ctx.router.xxx} in templates, but @click="handler" for events (no ctx.).


Documentation

Section Description
Configuration Routes, routing modes, options, layouts
Navigation Programmatic navigation, reactive state, events
Guards Navigation guards and lifecycle hooks
Lazy Loading Code splitting strategies
API Reference Complete API, error handling, plugins, TypeScript

Features

Feature Description
Multiple Routing Modes Hash (/#/path), History (/path), or Query (?view=/path)
Reactive State All route data exposed as Signals for reactive updates
Navigation Guards Control navigation flow with sync/async guards
Lifecycle Hooks Hook into navigation events for side effects
Lazy Loading Code-split components with dynamic imports
Layout System Wrap routes with reusable layout components
Plugin Architecture Extend router functionality with plugins
Scroll Management Built-in scroll position tracking
Dynamic Routes Add/remove routes at runtime
TypeScript-Friendly Comprehensive JSDoc type definitions

Installation

Prerequisites

Package Installation

# npm
npm install eleva

# yarn
yarn add eleva

# bun
bun add eleva

Import

// ES Modules (recommended)
import Eleva from "eleva";
import { Router } from "eleva/plugins";

// CommonJS
const Eleva = require("eleva");
const { Router } = require("eleva/plugins");

CDN

<!-- Option 1: Bundled plugins -->
<script src="https://cdn.jsdelivr.net/npm/eleva"></script>
<script src="https://cdn.jsdelivr.net/npm/eleva/dist/eleva-plugins.umd.min.js"></script>
<script>
  const app = new Eleva("MyApp");
  app.use(ElevaPlugins.Router, { /* options */ });
</script>

<!-- Option 2: Individual plugin -->
<script src="https://cdn.jsdelivr.net/npm/eleva"></script>
<script src="https://cdn.jsdelivr.net/npm/eleva/dist/plugins/router.umd.min.js"></script>
<script>
  const app = new Eleva("MyApp");
  app.use(ElevaRouter, { /* options */ });
</script>

Quick Start

This section walks through creating a basic single-page application with routing.

Step 1: Create Components

// File: components/HomePage.js
export const HomePage = {
  template: () => `
    <div class="page home-page">
      <h1>Welcome Home</h1>
      <p>This is the home page.</p>
      <nav>
        <a href="#/about">About</a>
        <a href="#/users/123">User 123</a>
      </nav>
    </div>
  `
};

// File: components/AboutPage.js
export const AboutPage = {
  template: () => `
    <div class="page about-page">
      <h1>About Us</h1>
      <a href="#/">Back Home</a>
    </div>
  `
};

// File: components/UserPage.js
export const UserPage = {
  setup(ctx) {
    // Access route params from context (params is a getter, no .value needed)
    const userId = ctx.router.params.id;
    return { userId };
  },
  template: (ctx) => `
    <div class="page user-page">
      <h1>User Profile</h1>
      <p>Viewing user ID: <strong>${ctx.userId}</strong></p>
      <a href="#/">Back Home</a>
    </div>
  `
};

// File: components/NotFoundPage.js
export const NotFoundPage = {
  template: () => `
    <div class="page not-found-page">
      <h1>404 - Page Not Found</h1>
      <a href="#/">Go Home</a>
    </div>
  `
};

Step 2: Set Up Router

// File: main.js
import Eleva from "eleva";
import { Router } from "eleva/plugins";
import { HomePage } from "./components/HomePage.js";
import { AboutPage } from "./components/AboutPage.js";
import { UserPage } from "./components/UserPage.js";
import { NotFoundPage } from "./components/NotFoundPage.js";

// 1. Create Eleva instance
const app = new Eleva("myApp");

// 2. Define routes
const routes = [
  { path: "/", component: HomePage },
  { path: "/about", component: AboutPage },
  { path: "/users/:id", component: UserPage },
  { path: "*", component: NotFoundPage }  // Catch-all (conventionally last)
];

// 3. Install router plugin (starts automatically by default)
const router = app.use(Router, {
  mode: "hash",      // Use hash-based routing
  mount: "#app",     // Mount point in HTML
  routes: routes
});

// Router starts automatically (autoStart: true by default)
// Use isReady signal to know when router is ready
router.isReady.watch((ready) => {
  if (ready) {
    console.log("Router started!");
    console.log("Current route:", router.currentRoute.value?.path);
  }
});

Step 3: HTML Structure

<!-- File: index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>My Eleva App</title>
</head>
<body>
  <!-- Router mounts here -->
  <div id="app"></div>

  <script type="module" src="./main.js"></script>
</body>
</html>

Expected Result

When you open the app:

  1. URL /#/ shows HomePage
  2. Click “About” → URL becomes /#/about, shows AboutPage
  3. Click “User 123” → URL becomes /#/users/123, shows UserPage with ID “123”
  4. Navigate to /#/unknown → shows NotFoundPage

Next Steps



← Back to Plugins Next: Configuration →