Skip to content
VersionSizeTypeScriptDependencies
Routeit Logo

Routeit

Routeit is a lightweight, type-safe client-side routing library for building modern single-page applications. It provides powerful features like middleware, nested routes, and permission integration with zero dependencies.

What Problem Does Routeit Solve?

Client-side routing is essential for SPAs, but most routers are either too complex, framework-specific, or lack proper TypeScript support. Routeit provides a clean, type-safe routing solution that works with any framework.

Traditional Approach:

ts
// Manual route handling
window.addEventListener('popstate', () => {
  const path = window.location.pathname;

  if (path === '/') {
    renderHome();
  } else if (path.startsWith('/users/')) {
    const id = path.split('/')[2];
    renderUser(id);
  } else if (path === '/about') {
    renderAbout();
  } else {
    render404();
  }
});

// Manual navigation
function navigate(path) {
  history.pushState(null, '', path);
  window.dispatchEvent(new PopStateEvent('popstate'));
}

With Routeit:

ts
import { createRouter } from '@vielzeug/routeit';

const router = createRouter();

router
  .get('/', () => renderHome())
  .get('/users/:id', ({ params }) => renderUser(params.id))
  .get('/about', () => renderAbout())
  .start();

// Navigate with built-in method
router.navigate('/users/123');

Comparison with Alternatives

FeatureRouteitReact RouterVue Router
Bundle Size2.1 KB~11KB~22KB
Dependencies0ReactVue
TypeScriptNativeGoodGood
Framework Agnostic
Middleware System

🚀 Key Features

  • Type-Safe Parameters – Automatic extraction and type inference
  • Middleware System – Powerful async middleware for auth, logging, and more
  • Framework Agnostic – Works with React, Vue, Svelte, or vanilla JS
  • Nested Routes – Support for child routes and layouts
  • Query Parameters – Automatic parsing and array support
  • Permission Integration – Works seamlessly with @vielzeug/permit
  • Hash & History Mode – Choose between hash-based or HTML5 History API
  • Named Routes – Navigate by name with parameter substitution
  • Lightweight – Only 2.1 KB gzipped, 0 dependencies

🏁 Quick Start

Install the package:

bash
pnpm add @vielzeug/routeit

Create a basic router:

ts
import { createRouter } from '@vielzeug/routeit';

const router = createRouter();

router
  .get('/', () => {
    document.getElementById('app').innerHTML = '<h1>Home</h1>';
  })
  .get('/about', () => {
    document.getElementById('app').innerHTML = '<h1>About</h1>';
  })
  .get('/users/:id', ({ params }) => {
    document.getElementById('app').innerHTML = `<h1>User ${params.id}</h1>`;
  })
  .start();

📚 Documentation

💡 Core Concepts

Route Parameters

Extract dynamic segments from URLs:

ts
router.get('/users/:userId/posts/:postId', ({ params }) => {
  console.log(params.userId); // '123'
  console.log(params.postId); // '456'
});
// Matches: /users/123/posts/456

Middleware

Execute code before route handlers:

ts
const requireAuth: Middleware = async (ctx, next) => {
  const user = await getCurrentUser();
  if (!user) {
    ctx.navigate('/login');
    return;
  }
  ctx.user = user;
  await next();
};

router.route({
  path: '/dashboard',
  middleware: requireAuth,
  handler: (ctx) => {
    console.log('User:', ctx.user);
  },
});

Query Parameters

Automatic query string parsing:

ts
router.get('/search', ({ query }) => {
  console.log(query.q); // 'test'
  console.log(query.filter); // ['new', 'sale']
});
// Matches: /search?q=test&filter=new&filter=sale

Named Routes

Navigate by route name:

ts
router.route({
  path: '/users/:id',
  name: 'userDetail',
  handler: ({ params }) => {
    console.log('User:', params.id);
  },
});

// Navigate using name
router.navigateTo('userDetail', { id: '123' });
// Or build URL
const url = router.urlFor('userDetail', { id: '123' }); // '/users/123'

❓ FAQ

Q: Can I use this with React/Vue/Svelte?
A: Yes! Routeit is framework-agnostic. See the Examples for integration examples.

Q: How do I handle authentication?
A: Use middleware! Check the Usage Guide for auth examples.

Q: Does it support nested routes?
A: Yes, through the children property. See Nested Routes.

Q: What about lazy loading?
A: Use async middleware to load route modules dynamically. See Examples.

Q: Can I integrate with @vielzeug/permit?
A: Absolutely! See the Permission Integration section.

🐛 Troubleshooting

Routes not matching:

  • Check path syntax – use :param for parameters
  • Ensure router is started with .start()
  • Verify base path configuration

Middleware not executing:

  • Make sure to call await next() to continue the chain
  • Check execution order (global → route → handler)

404 not working:

  • Provide a notFound handler in router options
  • Check if another route is matching first

Hash mode not working:

  • Ensure mode: 'hash' is set in router options
  • Check URL format includes # (e.g., #/about)

🤝 Contributing

Contributions are welcome! Please read our Contributing Guidelines.

📄 License

MIT © Vielzeug