Client Router
useRouter, useParams, Link, NavLink — the SPA navigation hooks.
On this page
Client Router
Inside islands and "use client" pages, Mandu's client router gives you
hooks and components for SPA-style navigation. It's the client-side
companion to the file-system router that picks which page.tsx to render.
All exports from @mandujs/core/client.
useRouter()
Imperative navigation + router state.
"use client";
import { useRouter } from "@mandujs/core/client";
export default function SettingsForm() {
const router = useRouter();
async function onSubmit(data: FormData) {
await saveSettings(data);
router.push("/account"); // client-side nav (no reload)
}
return <form action={onSubmit}>...</form>;
}
Available methods:
| Method | Effect |
|---|---|
router.push(href) |
Navigate, push history entry |
router.replace(href) |
Navigate, replace history entry |
router.back() |
Browser back |
router.refresh() |
Re-run the server render for the current URL |
router.pathname |
Current pathname |
router.query |
Parsed query string |
useParams()
Read the dynamic segments of the current route.
"use client";
import { useParams } from "@mandujs/core/client";
// Route: app/posts/[id]/comments.island.tsx
export default function Comments() {
const { id } = useParams<{ id: string }>();
// ...
}
For catch-all routes ([...slug]), the param is a string array.
<Link>
Declarative navigation. Intercepts clicks, prefetches on hover, falls back to a full-page navigation for external URLs.
import { Link } from "@mandujs/core/client";
<Link href="/docs/start/quickstart">Quickstart</Link>
<Link href="/docs" prefetch="hover">Docs home</Link>
<Link href="https://github.com/konamgil/mandu" target="_blank">GitHub</Link>
Props:
| Prop | Values | Default |
|---|---|---|
href |
Absolute path or external URL | — |
prefetch |
"hover" | "visible" | "eager" | false |
"hover" |
replace |
boolean — use replaceState instead of pushState |
false |
scroll |
boolean — scroll to top after nav |
true |
<NavLink>
Same as <Link> but adds an active class (or style) when the current URL
matches.
import { NavLink } from "@mandujs/core/client";
<NavLink
href="/docs/start"
activeClass="text-primary font-bold"
matchMode="startsWith"
>
Start
</NavLink>
matchMode:
"exact"(default) — active only on exact pathname match"startsWith"— active for any nested route (useful for top-level nav)
navigate() / prefetch() / subscribe()
Low-level primitives — usually you want useRouter or <Link>, but:
import { navigate, prefetch, subscribe } from "@mandujs/core/client";
// Programmatic nav outside React (e.g. from an event handler)
navigate("/dashboard");
// Warm the cache
prefetch("/docs/architect");
// React to every navigation
const unsub = subscribe((url, { direction }) => {
console.log("navigated to", url, direction);
});
subscribe is how smooth navigation
triggers page transitions.
Where you can use these
- Inside
.island.tsxfiles (must start with"use client") - Inside
"use client"pages - NOT inside server components — they throw at render time
For server-side redirects, use the Filling ctx.redirect() helper instead.
🤖 Agent Prompt
Apply the guidance from the Mandu docs page at https://mandujs.com/docs/reference/client-router to my project.
Summary of the page:
Mandu's client router (from @mandujs/core/client) mirrors React Router: useRouter for imperative navigation, useParams for route params, Link for declarative nav, NavLink for active-state links. Use inside islands or 'use client' pages.
Then:
1. Make the change in my codebase consistent with the page.
2. Run `bun run guard` and `bun run check` to verify nothing
in src/ or app/ breaks Mandu's invariants.
3. Show me the diff and any guard violations.
Related
- Client rendering — where these hooks apply
- Smooth navigation — SPA transition layer
- Rendering modes — when client nav fires
For Agents
Mandu's client router (from @mandujs/core/client) mirrors React Router: useRouter for imperative navigation, useParams for route params, Link for declarative nav, NavLink for active-state links. Use inside islands or 'use client' pages.