He
HeliumTS
Note:

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";
2
3export default function MyComponent() {
4 const router = useRouter();
5
6 // Access router properties
7 console.log(router.path);
8 console.log(router.params);
9 console.log(router.searchParams);
10 console.log(router.status);
11
12 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/123
2const router = useRouter();
3console.log(router.params.id); // "123"
4
5// 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=2
2const router = useRouter();
3console.log(router.searchParams.get("q")); // "hello"
4console.log(router.searchParams.get("page")); // "2"
5
6// Get all values as object
7const allParams = Object.fromEntries(router.searchParams);
8console.log(allParams); // { q: "hello", page: "2" }

status (200 | 404)

Current route status:

1const router = useRouter();
2
3if (router.status === 404) {
4 return <div>Page not found</div>;
5}
6
7return <div>Content</div>;

isNavigating (boolean)

Indicates whether a navigation is currently in progress. Useful for showing loading indicators:

1const router = useRouter();
2
3return (
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();
2
3return (
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();
2
3router.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();
2
3// Replace current URL (no back button entry)
4router.replace("/login");

on(event, listener)

Subscribe to router events. Returns an unsubscribe function:

1const router = useRouter();
2
3useEffect(() => {
4 // Listen to navigation events
5 const unsubscribe = router.on("navigation", (event) => {
6 console.log(`Navigated from ${event.from} to ${event.to}`);
7 });
8
9 // Cleanup
10 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 path
3 to: string; // New path
4 preventDefault?: () => void; // Only for "before-navigation"
5}

Fires after navigation completes:

1import { useRouter } from "heliumts/client";
2import { useEffect } from "react";
3
4export default function Analytics() {
5 const router = useRouter();
6
7 useEffect(() => {
8 const unsubscribe = router.on("navigation", (event) => {
9 // Track page view
10 trackPageView(event.to);
11 });
12
13 return unsubscribe;
14 }, [router]);
15
16 return null;
17}

Before Navigation Event

Fires before navigation and can be prevented:

1import { useRouter } from "heliumts/client";
2import { useEffect, useState } from "react";
3
4export default function UnsavedChangesGuard() {
5 const router = useRouter();
6 const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false);
7
8 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 );
14
15 if (!confirmed) {
16 event.preventDefault?.(); // Prevent navigation
17 }
18 }
19 });
20
21 return unsubscribe;
22 }, [router, hasUnsavedChanges]);
23
24 return <form>...</form>;
25}

TypeScript Support

Typing Route Params

1import { useRouter } from "heliumts/client";
2
3type UserPageParams = {
4 id: string;
5};
6
7export default function UserPage() {
8 const router = useRouter();
9 const { id } = router.params as UserPageParams;
10
11 // id is typed as string
12 return <div>User: {id}</div>;
13}

Typing Search Params

1import { useRouter } from "heliumts/client";
2
3export default function SearchPage() {
4 const router = useRouter();
5
6 const query = router.searchParams.get("q") ?? "";
7 const page = Number(router.searchParams.get("page") ?? "1");
8
9 // query: string, page: number
10 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";
2
3export 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