A universal router for Solid inspired by Ember and React Router
A universal router for Solid inspired by Ember and React Router
Solid Router brings fine-grained reactivity to route navigation, enabling your single-page application to become multi-paged without full page reloads. Fully integrated into the SolidJS ecosystem, Solid Router provides declarative syntax with features like universal rendering and parallel data fetching for best performance.
Explore the official documentation for detailed guides and examples.
# use preferred package manager
npm add @solidjs/routerInstall @solidjs/router, then start your application by rendering the router component
import { render } from "solid-js/web";
import { Router } from "@solidjs/router";
render(() => , document.getElementById("app"));This sets up a Router that will match on the url to display the desired page
Solid Router allows you to configure your routes using JSX:
Route component, specifying a path and a component to render when the user navigates to that path.import { render } from "solid-js/web";
import { Router, Route } from "@solidjs/router";
import Home from "./pages/Home";
import Users from "./pages/Users";
render(
() => (
),
document.getElementById("app")
);This will always be there and won't update on page change. It is the ideal place to put top level navigation and Context Providers
import { render } from "solid-js/web";
import { Router, Route } from "@solidjs/router";
import Home from "./pages/Home";
import Users from "./pages/Users";
const App = (props) => (
<>
My Site with lots of pages
{props.children}
);
render(
() => (
),
document.getElementById("app")
);We can create catch-all routes for pages not found at any nested level of the router. We use * and optionally the name of a parameter to retrieve the rest of the path.
import { render } from "solid-js/web";
import { Router, Route } from "@solidjs/router";
import Home from "./pages/Home";
import Users from "./pages/Users";
import NotFound from "./pages/404";
const App = (props) => (
<>
My Site with lots of pages
{props.children}
);
render(
() => (
),
document.getElementById("app")
);This way, the Users and Home components will only be loaded if you're navigating to /users or /, respectively.
import { lazy } from "solid-js";
import { render } from "solid-js/web";
import { Router, Route } from "@solidjs/router";
const Users = lazy(() => import("./pages/Users"));
const Home = lazy(() => import("./pages/Home"));
const App = (props) => (
<>
My Site with lots of pages
{props.children}
);
render(
() => (
),
document.getElementById("app")
);Use an anchor tag that takes you to a route:
import { lazy } from "solid-js";
import { render } from "solid-js/web";
import { Router, Route } from "@solidjs/router";
const Users = lazy(() => import("./pages/Users"));
const Home = lazy(() => import("./pages/Home"));
const App = (props) => (
<>
About
Home
My Site with lots of pages
{props.children}
);
render(
() => (
),
document.getElementById("app")
);If you don't know the path ahead of time, you might want to treat part of the path as a flexible parameter that is passed on to the component.
import { lazy } from "solid-js";
import { render } from "solid-js/web";
import { Router, Route } from "@solidjs/router";
const Users = lazy(() => import("./pages/Users"));
const User = lazy(() => import("./pages/User"));
const Home = lazy(() => import("./pages/Home"));
render(
() => (
),
document.getElementById("app")
);The colon indicates that id can be any string, and as long as the URL fits that pattern, the User component will show.
You can then access that id from within a route component with useParams.
Note on Animation/Transitions: Routes that share the same path match will be treated as the same route. If you want to force re-render you can wrap your component in a keyed `` like:
Each path parameter can be validated using a MatchFilter.
This allows for more complex routing descriptions than just checking the presence of a parameter.
import { lazy } from "solid-js";
import { render } from "solid-js/web";
import { Router, Route } from "@solidjs/router";
import type { MatchFilters } from "@solidjs/router";
const User = lazy(() => import("./pages/User"));
const filters: MatchFilters = {
parent: ["mom", "dad"], // allow enum values
id: /^\d+$/, // only allow numbers
withHtmlExtension: (v: string) => v.length > 5 && v.endsWith(".html"), // we want an `*.html` extension
};
render(
() => (
),
document.getElementById("app")
);Here, we have added the matchFilters prop. This allows us to validate the parent, id and withHtmlExtension parameters against the filters defined in filters.
If the validation fails, the route will not match.
So in this example:
/users/mom/123/contact.html would match,/users/dad/123/about.html would match,/users/aunt/123/contact.html would not match as :parent is not 'mom' or 'dad',/users/mom/me/contact.html would not match as :id is not a number,/users/dad/123/contact would not match as :withHtmlExtension is missing .html.Parameters can be specified as optional by adding a question mark to the end of the parameter name:
// Matches stories and stories/123 but not stories/123/comments
:param lets you match an arbitrary name at that point in the path. You can use * to match any end of the path:
// Matches any path that begins with foo, including foo/, foo/a/, foo/a/b/c
If you want to expose the wild part of the path to the component as a parameter, you can name it:
Note that the wildcard token must be the last part of the path; foo/*any/bar won't create any routes.
Routes also support defining multiple paths using an array. This allows a route to remain mounted and not rerender when switching between two or more locations that it matches:
// Navigating from login to register does not cause the Login component to re-render
The following two route definitions have the same result:
/users/:id renders the `` component, and /users/ is an empty route.
Only leaf Route nodes (innermost Route components) are given a route. If you want to make the parent its own route, you have to specify it separately:
//This won't work the way you'd expect
// This works
// This also works
You can also take advantage of nesting by using props.children passed to the route component.
function PageWrapper(props) {
return (
);
}
;The routes are still configured the same, but now the route elements will appear inside the parent element where the props.children was declared.
You can nest indefinitely - just remember that only leaf nodes will become their own routes. In this example, the only route created is /layer1/layer2, and it appears as three nested divs.
}
>
}
>
} />
Even with smart caches it is possible that we have waterfalls both with view logic and with lazy loaded code. With preload functions, we can instead start fetching the data parallel to loading the route, so we can use the data as soon as possible. The preload function is called when the Route is loaded or eagerly when links are hovered.
As its only argument, the preload function is passed an object that you can use to access route information:
import { lazy } from "solid-js";
import { Route } from "@solidjs/router";
const User = lazy(() => import("./pages/users/[id].js"));
// preload function
function preloadUser({ params, location }) {
// do preloading
}
// Pass it in the route definition
;| key | type | description |
|---|---|---|
| params | object | The route parameters (same value as calling useParams() inside the route component) |
| location | { pathname, search, hash, query, state, key} |
An object that you can use to get more information about the path (corresponds to useLocation()) |
No open issues yet, or sync has not completed.