HeliumTS is under pre-beta and active development. Expect bugs and breaking changes. If you find any issues, please report them in our GitHub
A stable release is planned for early December 2025.
useRouter Hook
Overview
The useRouter hook provides access to routing information and navigation methods.
1import { useRouter } from "heliumts/client";23export default function MyComponent() {4 const router = useRouter();56 // Access router properties7 console.log(router.path);8 console.log(router.params);9 console.log(router.searchParams);10 console.log(router.status);1112 return <div>...</div>;13}
Properties
path (string)
Current pathname (without query string):
1const router = useRouter();2console.log(router.path); // "/blog/my-post"
params (Record<string, string | string[]>)
Dynamic route parameters:
1// URL: /users/1232const router = useRouter();3console.log(router.params.id); // "123"45// URL: /docs/guide/getting-started (catch-all route)6const router = useRouter();7console.log(router.params.slug); // ["guide", "getting-started"]
searchParams (URLSearchParams)
URL query parameters:
1// URL: /search?q=hello&page=22const router = useRouter();3console.log(router.searchParams.get("q")); // "hello"4console.log(router.searchParams.get("page")); // "2"56// Get all values as object7const allParams = Object.fromEntries(router.searchParams);8console.log(allParams); // { q: "hello", page: "2" }
status (200 | 404)
Current route status:
1const router = useRouter();23if (router.status === 404) {4 return <div>Page not found</div>;5}67return <div>Content</div>;
isNavigating (boolean)
Indicates whether a navigation is currently in progress. Useful for showing loading indicators:
1const router = useRouter();23return (4 <div>5 {router.isNavigating && <LoadingSpinner />}6 <main>{/* page content */}</main>7 </div>8);
isPending (boolean)
Indicates when content is stale (React 18+ concurrent feature). True when React is rendering a new page in the background while still showing old content:
1const router = useRouter();23return (4 <div style={{ opacity: router.isPending ? 0.7 : 1 }}>5 <main>{/* page content */}</main>6 </div>7);
Methods
push(href: string)
Navigate to a new route (adds to history):
1const router = useRouter();23router.push("/about");4router.push("/users/123");5router.push("/search?q=hello");
replace(href: string)
Navigate to a new route (replaces current history entry):
1const router = useRouter();23// Replace current URL (no back button entry)4router.replace("/login");
on(event, listener)
Subscribe to router events. Returns an unsubscribe function:
1const router = useRouter();23useEffect(() => {4 // Listen to navigation events5 const unsubscribe = router.on("navigation", (event) => {6 console.log(`Navigated from ${event.from} to ${event.to}`);7 });89 // Cleanup10 return unsubscribe;11}, [router]);
Router Events
Event Types
"navigation": Fires after navigation completes"before-navigation": Fires before navigation (can be prevented)
Event Object
1{2 from: string; // Previous path3 to: string; // New path4 preventDefault?: () => void; // Only for "before-navigation"5}
Navigation Event
Fires after navigation completes:
1import { useRouter } from "heliumts/client";2import { useEffect } from "react";34export default function Analytics() {5 const router = useRouter();67 useEffect(() => {8 const unsubscribe = router.on("navigation", (event) => {9 // Track page view10 trackPageView(event.to);11 });1213 return unsubscribe;14 }, [router]);1516 return null;17}
Before Navigation Event
Fires before navigation and can be prevented:
1import { useRouter } from "heliumts/client";2import { useEffect, useState } from "react";34export default function UnsavedChangesGuard() {5 const router = useRouter();6 const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false);78 useEffect(() => {9 const unsubscribe = router.on("before-navigation", (event) => {10 if (hasUnsavedChanges) {11 const confirmed = window.confirm(12 "You have unsaved changes. Do you want to leave?"13 );1415 if (!confirmed) {16 event.preventDefault?.(); // Prevent navigation17 }18 }19 });2021 return unsubscribe;22 }, [router, hasUnsavedChanges]);2324 return <form>...</form>;25}
TypeScript Support
Typing Route Params
1import { useRouter } from "heliumts/client";23type UserPageParams = {4 id: string;5};67export default function UserPage() {8 const router = useRouter();9 const { id } = router.params as UserPageParams;1011 // id is typed as string12 return <div>User: {id}</div>;13}
Typing Search Params
1import { useRouter } from "heliumts/client";23export default function SearchPage() {4 const router = useRouter();56 const query = router.searchParams.get("q") ?? "";7 const page = Number(router.searchParams.get("page") ?? "1");89 // query: string, page: number10 return <div>Search: {query}, Page: {page}</div>;11}
Troubleshooting
useRouter throws "must be used inside <AppRouter>"
Cause: useRouter called outside the router context
Solution: Ensure you deleted /src/main.tsx and your /src/App.tsx is like this:
1import { type AppShellProps } from "heliumts/client";23export default function App({ Component, pageProps }: AppShellProps) {4 return <Component {...pageProps} />;5}
Dynamic params are undefined
Cause: Wrong param name or file structure
Solution: Ensure param name matches filename:
- File:
[id].tsx→ Param:router.params.id - File:
[slug].tsx→ Param:router.params.slug