@mycuppa/router
A lightweight, type-safe routing library for React applications with support for route parameters, query strings, and browser history.
Installation
npm install @mycuppa/router react react-dom
# or
pnpm add @mycuppa/router react react-dom
Quick Start
import { createRouter, setRouter, useRouter } from '@mycuppa/router'
// Create and configure router
const router = createRouter({
mode: 'history', // or 'hash'
routes: [
{ path: '/', handler: () => import('./pages/Home') },
{ path: '/about', handler: () => import('./pages/About') },
{ path: '/user/:id', handler: () => import('./pages/User') },
],
})
// Set as global router
setRouter(router)
// Use in components
function App() {
const { navigate, routeMatch } = useRouter()
return (
<div>
<nav>
<button onClick={() => navigate('/')}>Home</button>
<button onClick={() => navigate('/about')}>About</button>
</nav>
<p>Current path: {routeMatch?.path}</p>
</div>
)
}
Features
Route Parameters
Extract dynamic segments from URLs:
import { useParams } from '@mycuppa/router'
// Route: /user/:id
function UserProfile() {
const params = useParams()
return <h1>User ID: {params.id}</h1>
}
// Navigate to: /user/123
// params = { id: '123' }
Query Parameters
Parse and access query strings:
import { useQuery } from '@mycuppa/router'
// URL: /search?q=typescript&tags=web,mobile
function SearchResults() {
const query = useQuery()
return (
<div>
<p>Search: {query.q}</p>
{/* query.q = 'typescript' */}
<p>Tags: {query.tags?.join(', ')}</p>
{/* query.tags = ['web', 'mobile'] */}
</div>
)
}
Navigation
Programmatic navigation with multiple methods:
import { useRouter } from '@mycuppa/router'
function Navigation() {
const { navigate, back, forward, go } = useRouter()
return (
<div>
{/* Navigate to path */}
<button onClick={() => navigate('/about')}>About</button>
{/* Navigate with query params */}
<button
onClick={() => navigate('/search', { q: 'typescript' })}
>
Search
</button>
{/* Browser navigation */}
<button onClick={back}>Back</button>
<button onClick={forward}>Forward</button>
<button onClick={() => go(-2)}>Go back 2 pages</button>
</div>
)
}
Route Matching
Get current route information:
import { useRouteMatch } from '@mycuppa/router'
function CurrentRoute() {
const match = useRouteMatch()
if (!match) {
return <p>No route matched</p>
}
return (
<div>
<p>Path: {match.path}</p>
<p>Params: {JSON.stringify(match.params)}</p>
<p>Query: {JSON.stringify(match.query)}</p>
</div>
)
}
Configuration Options
import { createRouter } from '@mycuppa/router'
const router = createRouter({
// Routing mode
mode: 'history', // or 'hash'
// Base path for all routes
basePath: '/app',
// Route definitions
routes: [
{ path: '/', handler: async () => import('./pages/Home') },
{ path: '/about', handler: async () => import('./pages/About') },
{ path: '/user/:id', handler: async () => import('./pages/User') },
{
path: '/blog/:slug',
handler: async () => import('./pages/BlogPost'),
},
],
})
Advanced Usage
Route Guards
Protect routes with authentication:
import { useRouter } from '@mycuppa/router'
import { useAuth } from '@mycuppa/auth'
function ProtectedRoute({ children }) {
const { navigate } = useRouter()
const { isAuthenticated } = useAuth()
if (!isAuthenticated) {
navigate('/login')
return null
}
return <>{children}</>
}
Lazy Loading
Routes support lazy loading with React.lazy:
import { lazy, Suspense } from 'react'
const Home = lazy(() => import('./pages/Home'))
const About = lazy(() => import('./pages/About'))
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<Home />
</Suspense>
)
}
Custom Link Component
import { useRouter } from '@mycuppa/router'
function Link({
to,
children,
...props
}: {
to: string
children: React.ReactNode
}) {
const { navigate } = useRouter()
const handleClick = (e: React.MouseEvent) => {
e.preventDefault()
navigate(to)
}
return (
<a href={to} onClick={handleClick} {...props}>
{children}
</a>
)
}
// Usage
<Link to="/about">About Us</Link>
API Reference
createRouter(config)
Create a new router instance.
Config:
mode?: 'history' | 'hash'- Routing mode (default: 'history')basePath?: string- Base path for all routesroutes: Route[]- Route definitions
Returns: Router instance
Router Methods
navigate(path, query?)- Navigate to a pathback()- Go back in historyforward()- Go forward in historygo(delta)- Go to a specific history offsetmatch(path)- Match a path against routessubscribe(callback)- Subscribe to route changes
React Hooks
useRouter()- Get router instance and stateuseRouteMatch()- Get current route matchuseParams()- Get route parametersuseQuery()- Get query parameters
Route Object
interface Route {
path: string // Route path pattern
handler: () => Promise<any> // Lazy import function
}
RouteMatch Object
interface RouteMatch {
path: string // Matched path
params: Record<string, string> // Route parameters
query: Record<string, string | string[]> // Query parameters
}
Best Practices
- Use history mode - Prefer history over hash mode for cleaner URLs
- Lazy load routes - Use dynamic imports for code splitting
- Type-safe params - Validate route parameters at runtime
- Query arrays - Use
tags=a&tags=bformat for array query params - Route guards - Implement authentication checks in components
Examples
See the examples directory for complete routing examples.