FUNSTACK Router

HomeGetting StartedLearnAPI ReferenceExamplesFAQ
GitHub

Built with @funstack/router — A modern React router based on the Navigation API

Getting Started

Installation

Install the package using your preferred package manager:

npm install @funstack/router
# or
pnpm add @funstack/router
# or
yarn add @funstack/router

AI Coding Agent Support

@funstack/router ships with an Agent skill that gives your coding assistant (Claude Code, Cursor, GitHub Copilot, etc.) knowledge about the router's API and best practices. Run:

npx -p @funstack/router funstack-router-skill-installer
# or
pnpm dlx --package @funstack/router funstack-router-skill-installer
# or
yarn dlx -p @funstack/router funstack-router-skill-installer

The installer will guide you through setting up the skill for your preferred AI agent. Alternatively, if you prefer npx skills, you can install it with:

npx skills add uhyo/funstack-router

Browser Support

FUNSTACK Router uses the Navigation API which is supported in Chrome 102+, Edge 102+, Firefox 147+, Safari 26.2+.

Basic Setup

Create your routes using the route helper function and render them with the Router component:

import { Router, route, Outlet } from "@funstack/router";

// Define your page components
function Home() {
  return <h1>Welcome Home</h1>;
}

function About() {
  return <h1>About Us</h1>;
}

function Layout() {
  return (
    <div>
      <nav>
        <a href="/">Home</a>
        <a href="/about">About</a>
      </nav>
      <Outlet />
    </div>
  );
}

// Define your routes
const routes = [
  route({
    path: "/",
    component: Layout,
    children: [
      route({ path: "/", component: Home }),
      route({ path: "/about", component: About }),
    ],
  }),
];

// Render the router
function App() {
  return <Router routes={routes} />;
}

Route Parameters

Define dynamic segments in your paths using the :param syntax. Route components receive parameters via the params prop, which is fully typed based on the path pattern:

import { route } from "@funstack/router";

function UserProfile({ params }: { params: { userId: string } }) {
  return <h1>User: {params.userId}</h1>;
}

const routes = [
  route({
    path: "/users/:userId",
    component: UserProfile,
  }),
];

Data Loading

Use the loader option to fetch data before rendering a route. The component receives both data (from the loader) and params (from the URL) as props:

import { route } from "@funstack/router";

interface User {
  id: string;
  name: string;
}

function UserProfilePage({
  data,
  params,
}: {
  data: Promise<User>;
  params: { userId: string };
}) {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <UserProfile data={data} params={params} />
    </Suspense>
  );
}

function UserProfile({
  data,
  params,
}: {
  data: Promise<User>;
  params: { userId: string };
}) {
  const user = use(data);
  return (
    <div>
      <h1>{user.name}</h1>
      <p>User ID: {params.userId}</p>
    </div>
  );
}

const userRoute = route({
  path: "/users/:userId",
  component: UserProfilePage,
  loader: async ({ params }): Promise<User> => {
    const response = await fetch(`/api/users/${params.userId}`);
    return response.json();
  },
});