Routing utilities for terminal applications.
@termuijs/router provides screen-based navigation for terminal UIs with support for manual route registration, file-system routing, dynamic route parameters, navigation history, guards, and error boundaries.
The router is designed for predictable navigation flow while keeping screen management lightweight and memory-safe.
npm install @termuijs/routerRequires @termuijs/core and @termuijs/widgets.
Routes can be registered programmatically using screen names and widget instances.
import { Router } from '@termuijs/router'
const router = new Router()
router.register('home', homeWidget)
router.register('settings', settingsWidget)
router.register('help', helpWidget)
router.push('settings')
router.back()
console.log(router.current)| Method | Description |
|---|---|
register(name, screen) |
Registers a screen with the router |
push(route) |
Navigates to a new route |
back() |
Navigates to the previous route |
guard(route, handler) |
Adds a navigation guard |
current |
Returns the active route |
history |
Returns the navigation history stack |
The router can automatically generate routes from a directory structure.
Each file inside the configured directory becomes a route.
screens/
index.ts -> /
settings.ts -> /settings
help.ts -> /help
users/
[id].ts -> /users/[id]
const router = new Router({
dir: './screens',
})
router.push('/users/42')Dynamic routes automatically receive extracted parameters.
Dynamic route segments use bracket syntax.
Parameters are passed directly into the screen component.
// screens/logs/[level].ts
export default function LogScreen({ params }) {
const { level } = params
return <LogView filter={level} />
}Navigating to:
/logs/error
Provides:
params = {
level: 'error'
}| Pattern | Example Route | Result |
|---|---|---|
[id] |
/users/42 |
{ id: '42' } |
[level] |
/logs/warn |
{ level: 'warn' } |
| Nested params | /users/42/posts/7 |
Multiple extracted params |
The router maintains an internal navigation stack for backward navigation and route tracking.
router.push('/settings')
router.push('/help')
router.back()History entries are stored in:
router.history| Action | Result |
|---|---|
push() |
Adds a new route to the stack |
back() |
Removes the current route and returns to the previous route |
history |
Exposes the complete navigation stack |
| Route change | Previous screen fibers are safely unmounted |
The router automatically cleans up inactive screen fibers before mounting new screens, helping prevent stale state and memory leaks.
All routed screens are wrapped in an internal ErrorBoundary.
If a screen throws an exception during rendering, the router prevents the application from crashing and displays a fallback error screen instead.
const router = new Router({
dir: './screens',
errorFallback: (err) => (
<Box borderColor="red">
<Text color="red">
Screen error: {err.message}
</Text>
</Box>
),
})| Option | Type | Description |
|---|---|---|
errorFallback |
(error: Error) => Widget |
Custom UI displayed when a routed screen throws |
Guards allow routes to be conditionally blocked or redirected before navigation completes.
Return:
trueto allow navigationfalseto block navigation- a route path to redirect
router.guard('/settings', () => {
if (!isAuthenticated) {
return '/login'
}
return true
})| Return Value | Result |
|---|---|
true |
Navigation continues |
false |
Navigation is blocked |
'/path' |
Navigation redirects to another route |
| Option | Type | Description |
|---|---|---|
dir |
string |
Directory used for automatic file-based routing |
errorFallback |
(error: Error) => Widget |
Custom error screen renderer |
Additional documentation is available at:
https://www.termui.io/docs/router/overview
MIT
@termuijs/router provides screen-based routing for terminal applications. Routes are registered with a Router instance and matched against URL-like paths. The router manages navigation history, route parameters, nested routes, query parameters, guards, redirects, and screen rendering.
The routing model is screen-oriented: navigating to a path resolves a matching route, extracts any parameters, and renders the associated screen component.
Routes are defined using the Route type and registered on a Router instance. Router behavior can be customized with RouterOptions.
import {
Router,
type Route,
type RouterOptions,
} from '@termuijs/router'
function HomeScreen() {
return null
}
function SettingsScreen() {
return null
}
const options: RouterOptions = {
initialPath: '/',
maxHistory: 50,
}
const router = new Router(options)
router.addRoute('/', HomeScreen)
router.addRoute('/settings', SettingsScreen)
router.push('/settings')RouterOptions supports:
initialPath– initial route to navigate tomaxHistory– maximum history entries to retainnotFound– fallback renderer when no route matches
Routes can contain child routes using the children property. The matchRoute utility resolves nested route structures and returns a RouteMatch.
import {
matchRoute,
type Route,
} from '@termuijs/router'
const routes: Route[] = [
{
path: '/users',
component: () => null,
children: [
{
path: 'profile',
component: () => null,
},
],
},
]
const match = matchRoute('/users/profile', routes)
if (match) {
console.log(match.route.path)
console.log(match.chain)
}The returned RouteMatch.chain contains the matched route hierarchy from parent to child.
Dynamic route segments use bracket syntax and are compiled using compilePattern.
import {
compilePattern,
matchRoute,
type Route,
type RouteMatch,
type RouteParams,
} from '@termuijs/router'
const { pattern, paramNames } = compilePattern('/users/[id]')
console.log(pattern)
console.log(paramNames)
const routes: Route[] = [
{
path: '/users/[id]',
component: () => null,
},
]
const match: RouteMatch | null = matchRoute('/users/42', routes)
if (match) {
const params: RouteParams = match.params
console.log(params.id)
}RouteMatch contains:
route– the matched route definitionchain– parent-to-child route chainparams– extracted route parametersmeta– route metadataquery– parsed query parameters
The router exposes hooks for accessing route state and performing navigation inside components.
useParams() returns the current route parameters.
import { useParams } from '@termuijs/router'
function UserScreen() {
const params = useParams()
console.log(params.id)
return null
}useNavigate() returns a navigation function.
import { useNavigate } from '@termuijs/router'
function HomeScreen() {
const navigate = useNavigate()
function openSettings() {
navigate('/settings')
}
function openProfile() {
navigate('/users/42', {
query: {
tab: 'activity',
},
})
}
function replaceRoute() {
navigate('/login', {
replace: true,
})
}
return null
}The navigation function signature is:
(path: string, options?: {
replace?: boolean
query?: QueryParams
}) => void