| name | solid-impl-routing |
| description | Use when implementing client-side routing, navigation, or URL parameter handling in SolidJS applications. Prevents incorrect router setup, misused navigation hooks, and non-lazy-loaded route bundles. Covers Router/HashRouter setup, A component, useNavigate, useParams, useSearchParams, useBeforeLeave, lazy loading, route preloading, and config-based routing. Keywords: @solidjs/router, Route, useNavigate, useParams, useSearchParams, lazy, route guard, client-side routing.
|
| license | MIT |
| compatibility | Designed for Claude Code. Requires @solidjs/router 0.15+ with SolidJS 1.x/2.x and TypeScript. |
| metadata | {"author":"OpenAEC-Foundation","version":"1.0"} |
solid-impl-routing
Quick Reference
Installation
npm install @solidjs/router
Requires SolidJS v1.8.4 or later.
Router Types
| Router | URL Style | Use Case |
|---|
Router | /path | Production apps with server support |
HashRouter | /#/path | Static hosting without server rewrites |
MemoryRouter | In-memory | Testing, no browser history |
Hook Quick Reference
| Hook | Returns | Purpose |
|---|
useNavigate() | (to, options?) => void | Programmatic navigation |
useParams() | Params | Dynamic route parameter values |
useSearchParams() | [params, setParams] | Query string read/write |
useLocation() | Location | Current pathname, search, hash, state |
useMatch(() => path) | Accessor<Match | undefined> | Check if path matches current route |
useIsRouting() | Accessor<boolean> | True during navigation transitions |
useBeforeLeave(callback) | void | Route guard (unsaved changes warning) |
usePreloadRoute() | (href) => void | Trigger preloading on hover |
useCurrentMatches() | Accessor<Match[]> | All matched route segments |
React Router vs Solid Router
| Concept | React Router (WRONG) | Solid Router (CORRECT) |
|---|
| Link component | <Link to="/path"> | <A href="/path"> |
| Route element | element={<Home />} | component={Home} |
| Router hook | useRouter() | useNavigate() |
| Lazy import | React.lazy(...) | lazy(...) from solid-js |
| Loader data | useLoaderData() | createAsync(() => query(...)) |
| Route loader | loader prop | preload prop |
Critical Warnings
NEVER use element={<Component />} on a Route. This React pattern creates the component immediately, bypassing Solid Router's deferred rendering. ALWAYS use component={Component} (passing the reference, not a JSX call).
NEVER import Link from @solidjs/router — the component is called A, not Link. Using Link causes an import error.
NEVER import useRouter — this does not exist in Solid Router. ALWAYS use useNavigate() for programmatic navigation.
NEVER destructure useParams() at the top level — the returned object is a reactive proxy. Destructuring breaks reactivity. ALWAYS access params.id directly in JSX or inside tracked scopes.
NEVER call useSearchParams()[1] with a full replacement object expecting it to clear other params — it merges by default. To remove a param, set it to undefined.
Router Setup
Basic Router with JSX Routes
import { Router, Route } from "@solidjs/router";
import { lazy } from "solid-js";
import { render } from "solid-js/web";
const Home = lazy(() => import("./pages/Home"));
const About = lazy(() => import("./pages/About"));
const User = lazy(() => import("./pages/User"));
function App() {
return (
<Router>
<Route path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/users/:id" component={User} />
</Router>
);
}
render(() => <App />, document.getElementById("root")!);
Router with Root Layout
import { Router, Route } from "@solidjs/router";
import type { RouteSectionProps } from "@solidjs/router";
function Layout(props: RouteSectionProps) {
return (
<div>
<nav>
<A href="/">Home</A>
<A href="/about">About</A>
</nav>
<main>{props.children}</main>
</div>
);
}
function App() {
return (
<Router root={Layout}>
<Route path="/" component={Home} />
<Route path="/about" component={About} />
</Router>
);
}
Config-Based Routing
import { Router } from "@solidjs/router";
import type { RouteDefinition } from "@solidjs/router";
import { lazy } from "solid-js";
const routes: RouteDefinition[] = [
{ path: "/", component: lazy(() => import("./pages/Home")) },
{ path: "/about", component: lazy(() => import("./pages/About")) },
{
path: "/users",
component: lazy(() => import("./pages/Users")),
children: [
{ path: "/:id", component: lazy(() => import("./pages/UserDetail")) },
],
},
];
function App() {
return <Router>{routes}</Router>;
}
Navigation
The <A> Component
import { A } from "@solidjs/router";
<A href="/dashboard">Dashboard</A>
<A href="/users" activeClass="font-bold" inactiveClass="text-gray" end>Users</A>
<A href="/settings" replace noScroll state={{ from: "nav" }}>Settings</A>
ALWAYS use end on root paths (/) to prevent matching every route.
Programmatic Navigation
import { useNavigate } from "@solidjs/router";
function LoginButton() {
const navigate = useNavigate();
const handleLogin = async () => {
await performLogin();
navigate("/dashboard", { replace: true });
};
return <button onClick={handleLogin}>Log In</button>;
}
Navigate Component (Redirect)
import { Navigate } from "@solidjs/router";
import { Show } from "solid-js";
function ProtectedRoute(props: RouteSectionProps) {
const user = useUser();
return (
<Show when={user()} fallback={<Navigate href="/login" />}>
{props.children}
</Show>
);
}
Route Parameters and Search Params
Dynamic Parameters
import { useParams } from "@solidjs/router";
function UserProfile() {
const params = useParams();
return <h1>User: {params.id}</h1>;
}
Search Parameters
import { useSearchParams } from "@solidjs/router";
function ProductList() {
const [search, setSearch] = useSearchParams();
return (
<div>
<p>Page: {search.page ?? "1"}</p>
<button onClick={() => setSearch({ page: String(Number(search.page ?? 1) + 1) })}>
Next Page
</button>
</div>
);
}
Route Guards
import { useBeforeLeave } from "@solidjs/router";
import { createSignal } from "solid-js";
function EditForm() {
const [dirty, setDirty] = createSignal(false);
useBeforeLeave((e) => {
if (dirty() && !e.defaultPrevented) {
e.preventDefault();
if (window.confirm("Discard unsaved changes?")) {
e.retry(true);
}
}
});
return <textarea onInput={() => setDirty(true)} />;
}
Lazy Loading and Preloading
Lazy Route Components
import { lazy } from "solid-js";
const Dashboard = lazy(() => import("./pages/Dashboard"));
const Settings = lazy(() => import("./pages/Settings"));
<Route path="/dashboard" component={Dashboard} />
<Route path="/settings" component={Settings} />
Route Preloading
import { Route, query, createAsync } from "@solidjs/router";
import type { RoutePreloadFuncArgs } from "@solidjs/router";
const getProduct = query(async (id: string) => {
const res = await fetch(`/api/products/${id}`);
return res.json();
}, "product");
function preloadProduct({ params }: RoutePreloadFuncArgs) {
getProduct(params.id);
}
<Route path="/products/:id" component={ProductPage} preload={preloadProduct} />
Hover Preloading
import { usePreloadRoute } from "@solidjs/router";
function NavBar() {
const preload = usePreloadRoute();
return (
<nav>
<A href="/dashboard" onMouseEnter={() => preload("/dashboard")}>
Dashboard
</A>
</nav>
);
}
Nested Routes
<Router>
<Route path="/users" component={UsersLayout}>
<Route path="/" component={UsersList} />
<Route path="/:id" component={UserDetail} />
<Route path="/:id/settings" component={UserSettings} />
</Route>
</Router>
The parent UsersLayout receives props.children which renders the matched child route.
Route Match Filters
<Route
path="/users/:id"
component={UserPage}
matchFilters={{ id: /^\d+$/ }}
/>
The route only matches when id is numeric. Non-matching URLs fall through to other routes or 404.
Reference Links
- references/methods.md -- API signatures for Router, Route, A, Navigate, and all hooks
- references/examples.md -- Working code examples for router setup, navigation, guards, lazy loading, preloading, nested routes
- references/anti-patterns.md -- React Router patterns that break Solid Router, with corrections
Official Sources