Router
Signal-based client-side routing. Configure the router with @RouterConfig on your root component and use decorator-based injection to access router state anywhere.
npm install @praxisjs/routerpnpm add @praxisjs/routeryarn add @praxisjs/routerbun add @praxisjs/routerSetup with @RouterConfig
Apply @RouterConfig to the root component class to configure the router.
Each entry can be a full RouteDefinition object, or a class decorated with @Route (the path is read automatically):
import { RouterConfig, Route, Lazy } from '@praxisjs/router'
import { RouterView } from '@praxisjs/router'
import { Home } from './pages/Home' // decorated with @Route('/')
import { About } from './pages/About' // decorated with @Route('/about')
@RouterConfig([
Home, // path from @Route
About, // path from @Route
{ path: '/users/:id', component: Lazy(() => import('./pages/UserDetail')) },
{
path: '/admin',
component: Lazy(() => import('./pages/AdminLayout')),
children: [
{ path: 'users', component: Lazy(() => import('./pages/AdminUsers')) },
{ path: 'settings', component: Lazy(() => import('./pages/AdminSettings')) },
],
},
{ path: '**', component: Lazy(() => import('./pages/NotFound')) },
])
@Component()
class App extends StatefulComponent {
render() {
return (
<div>
<NavBar />
<RouterView />
</div>
)
}
}RouterView renders the matched route component reactively.
@Route(path)
Co-locates the route path with the component. When you pass the class directly to @RouterConfig, the path is read automatically — no duplication needed.
// pages/About.tsx
@Route('/about')
@Component()
export default class About extends StatefulComponent {
render() { return <main>About</main> }
}// app.tsx
import About from './pages/About'
@RouterConfig([About]) // path comes from @Route
@Component()
class App extends StatefulComponent { ... }You can still use the explicit object form when you need children, beforeEnter, or other options:
@RouterConfig([
{ path: About.__routePath, component: About, beforeEnter: authGuard },
])@Lazy(loader)
Marks a class as a lazy-loaded route component. The actual component is loaded on first navigation and cached.
@Lazy(() => import('./pages/UserDetail'))
class UserDetailPage {}
// Use as a component in route definitions:
{ path: '/users/:id', component: UserDetailPage }Or inline directly in the route definition:
{ path: '/users/:id', component: Lazy(() => import('./pages/UserDetail')) }Default export required
Pages loaded via Lazy must use export default. The loader resolves module.default at runtime.
// pages/UserDetail.tsx
@Route('/users/:id')
@Component()
export default class UserDetail extends StatefulComponent { ... }Injecting router state
Use these field decorators to access reactive router state inside any component or service.
@InjectRouter()
Injects the Router instance for navigation and loading state:
import { InjectRouter } from '@praxisjs/router'
@Component()
class NavBar extends StatefulComponent {
@InjectRouter() router!: Router
render() {
return (
<nav>
{() => this.router.loading() && <Spinner />}
<button onClick={() => this.router.push('/home')}>Home</button>
</nav>
)
}
}@Params()
Injects current route params as a reactive Computed:
@Params() params!: Computed<RouteParams>
render() {
return <p>User ID: {() => this.params().id}</p>
}@Query()
Injects the URL query string as a reactive Computed:
@Query() query!: Computed<RouteQuery>
render() {
return <p>Page: {() => this.query().page ?? '1'}</p>
}@Location()
Injects the full current route location as a reactive Signal:
@Location() location!: Signal<RouteLocation>
render() {
return <p>Path: {() => this.location().path}</p>
}RouteLocation has path, params, query, and hash.
Navigation
await this.router.push('/users/42') // navigate, add to history
await this.router.push('/search', { q: 'foo' }) // with query params
await this.router.replace('/login') // replace current entry
this.router.back()
this.router.forward()
this.router.go(-2)Link component
import { Link } from '@praxisjs/router'
<Link to="/home">Home</Link>
<Link to="/users" activeClass="nav-active">Users</Link>
<Link to="/settings" replace>Settings</Link>| Prop | Type | Description |
|---|---|---|
to | string | Target path |
replace | boolean | Use replace instead of push |
activeClass | string | Class added when route is active |
Navigation guards
Add beforeEnter to any route. Return true to allow, false to cancel, or a path string to redirect:
{
path: '/admin',
component: AdminPage,
beforeEnter: async (to, from) => {
const ok = await auth.checkPermission(to.path)
return ok ? true : '/login'
},
}