Solid Router simplifies routing in Solid applications to help developers manage navigation and rendering. Solid Router supports defining routes using JSX or objects passed via props. This section will focus on the practical implementation of Solid Router using JSX.
### Getting Started
#### Set Up the Router
1. Install `@solidjs/router` since it is not included by default.
```bash
npm install @solidjs/router
# or
yarn add @solidjs/router
# or
pnpm i @solidjs/router
```
2. Import the `Router` component to wrap the root component.
```jsx=
import {render} from "solid-js/web"
import App from "./App"
import {Router} from "@solidjs/router"
render(
() => (
<Router>
<App/>
</Router>
),
document.getElementById("root")
)
```
This allows the routes to be displayed throughout the entire application.
#### Configure the Routes
Solid Router offers a convenient way to configure routes using `JSX` syntax:
1. Use the `Routes` component to specify where the routes should appear in the application.
```jsx=
import { Routes, Route } from "@solidjs/router";
export default function App() {
return (
<>
<h1>This is my site</h1>
<Routes>
// Routes will go here
</Routes>
</>
);
}
```
2. The `Route` component takes a `path` prop, which specifies what path or element to render when navigated to. When this path is successfully matched, the `component` or `element` prop will be triggered, rendering what it corresponds to.
For grouping multiple routes, or for nesting, the `Routes` component must be used. For example:
```jsx=
import { Routes, Route } from "@solidjs/router";
import Home from "./pages/Home";
import About from "./pages/About";
export default function App() {
return (
<>
<h1>My Site with many pages</h1>
<Routes>
<Route path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/wow" element={<div>You can even do this!</div>} />
</Routes>
</>
);
}
```
### Creating links to Routes
#### The `A` Component
The `A` component creates an anchor tag that creates routes within an application. Additionally, the component takes in an `href` prop which is the URL path that the link will navigate to.
Using the `A` component would look like the following:
```jsx=
import { A } from "@solidjs/router";
export default function App() {
return (
<div>
<header>
<A
href="/home"
>
Home
</A>
<A
href="/about"
>
About
</A>
</header>
</div>
);
};
```
The `A` component can also take in the `activeClass` prop, which is a class that will be applied when the current location matches the `href` prop.
```jsx=
import { A } from "@solidjs/router";
export default function App() {
return (
<div>
<header>
<p>
Edit <code>src/App.tsx</code> and save to reload.
</p>
<A
href="/about"
>
Home
</A>
<A
href="/about"
activeClass="underlined" // 👈 When active, this link will now be underlined.
>
About
</A>
</header>
</div>
);
};
```
##### `A` Component Props
| prop | type | description|
| ------------- | ------- | ---------- |
| href | string | Indicates the URL path to navigate to, which must start with a forward slash ("/").|
| noScroll | boolean | If `true`, the default behavior of scrolling to the top of the new page will be turned off.|
| replace | boolean | If set to `true`, the new page will not be added to the browser history, allowing the back button to navigate to the previous route. By default, the new page is added to the browser history.|
| state | serializable object | Passes a serialized object to the history stack during navigation. When the user navigates to the new state, an event is triggered, granting access to a copy of the state object associated with that particular entry in the browsing history. See [`history.pushState()`](https://developer.mozilla.org/en-US/docs/Web/API/History/pushState) for more info. |
| inactiveClass | string | Will specifies the CSS class to apply when the location and `href` prop do not match.|
| activeClass | string | The CSS class that will be applied when the location and `href` prop match.|
| end | boolean | When set to `true`, the link is considered active only when the current location exactly matches the `href`. However, when set to `false`, the link is considered active if the current location *starts* with the `href` value.|
#### The `Navigate` component
The `Navigate` component which functions similarly to `A`. It, however, has the added capability of instantly navigating to the specified path as soon as the component is rendered. This is often used to express redirects.
```jsx =
<Route path="/redirect" element={<Navigate href="/login" />}/>
```
### Nested Routes
Solid Router supports nested routes, allowing for more complex routing structures.
```jsx=
// Nested routes can be written as a single route
<Route path="/about/me" component={User} />
// Or they can be defined separately
<Route path="/about">
<Route path="/me" component={User} />
</Route>
```
However, only leaf `Route` nodes, or the innermost`Route`, will be given a route. To ensure the parent has its own route, it must be specified separately.
```jsx
<Route path="/about" component={About}> // This won't work
<Route path="/me" component={User} />
</Route>
// This will work
<Route path="/about" component={About} />
<Route path="/about/me" component={Me} />
// This will also work
<Route path="/about">
<Route path="/" component={About} />
<Route path="/me" component={Me} />
</Route>
```
#### The `<Outlet />` Component
Nested routes can also take advantage of the `<Outlet />` component to render the nested content within a parent component. The `<Outlet />` component serves as a placeholder that will be be replaced with the content of the matched child route.
Here's an example of how to use nested routes with `<Outlet/>`:
```jsx=
import { Outlet } from "@solidjs/router";
function PageWrapper() {
return (
<div>
<h1>Solid is great!</h1>
<Outlet />
<A href="/">Back Home</A>
</div>
);
}
<Route path="/about" component={PageWrapper}>
<Route path="/" component={About} />
<Route path="/me" component={User} />
</Route>
```
In this example, the `<Outlet />` component is used to specify where the content of the child routes should be rendered within the `PageWrapper` component.
With this example, when the `/about` route is matched, the `PageWrapper` component will be rendered, and the content of the child routes (`About` and `Me`) will be rendered inside the <Outlet/> component.
This approach allows you to define a shared layout or container component for a group of nested routes and render the specific element based on the child routes.
You can nest routes indefinitely using this approach, as long as you have the appropriate parent components `<Outlet />` placeholders defined at each level.
### Dynamic Routing
Dynamic routing lets an application handle URLs where some segments are not known ahead of time. In Solid, you can create a dynamic route by using a colon (:) before a segment in the `path` prop of a `Route` component. This indicates that the segment can be any string.
```jsx=
import { Routes, Route } from "@solidjs/router";
import Home from "./pages/Home";
import About from "./pages/About"
import User from "./pages/User";
export default function App() {
return (
<>
<h1>My Site with many pages</h1>
<Routes>
<Route path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/user/:id" component={User} />
<Route path="/wow" element={<div>You can even do this!</div>} />
</Routes>
</>
);
}
```
In the example above, the `:id` in the `/user/:id` path will be treated as a parameter. As long as the URL matches this pattern, the User component will be displayed.
### Parameter Validation
When working with dynamic routes, it is often necessary to validate the route parameters to ensure they meet certain criteria. Solid provides a convenient way to perform this task through `MatchFilters`.
`MatchFilters` provides the option to define validation rules for each parameter in the route path. By including the `matchFilters={filters}` prop in the `<Route>` component, the parameters in the route path are automatically validated against their respective filters. If any validation fails, the route will not be matched.
Here's an example of how `MatchFilters` can be used:
```jsx=
//...
const filters: MatchFilters = {
parent: ["mom", "dad"], // allow enum values
id: /^\d+$/, // only allow numbers
withHtmlExtension: (v: string) => v.length > 5 && v.endsWith(".html"), // custom validation function
};
export default function App() {
// ...
return (
<>
<h1>My Site with Lots of Pages</h1>
<Routes>
<Route
path="/users/:id/:/parent/:withHtmlExtension"
component={User}
matchFilters={filters}
/>
</Routes>
</>
);
}
```
In this example, the `filters` object defines the validation rules for each parameter:
- The `parent` parameter allows only the values `"mom"` or `"dad"`.
- The `id` parameter allows only numeric values.
- The `withHtmlExtension` parameter is validated using a custom function that checks for a length greater than 5 and a `".html"` extension.
In this example, the following would match:
- `/user/mom/123/contact.html`
- `/user/dad/123/about.html`
While these wouldn't:
- /user/123/aunt/contact.html - `:parent` is not `"mom"` or `"dad"`,
- /user/123/mom/me/contact.html - `:id` is not a number
- /users/dad/contact - `:withHtmlExtension` is missing `.html`
### Optional Parameters
Routes can be specified as optional by adding `?` to the end of a parameter name. This allows for more flexible routing pattersn where certain segments of the path my or may not be present.
```jsx
<Route path="/stories/:id?" element={<Stories />} />
```
### Wildcard Routes
Wildcard routes allow matching of an arbitrary part of the path. The wildcard token (`*`) can be used to represent any value in that segment of the path. Additionally, this value can be exposed as a parameter to the component.
To demonstrate this, consider the following:
```jsx
<Route path="foo/*" component={Foo} />
```
In this example, the route path `"foo/*"` matches any path that begins with `"foo"`. This includes paths like `"foo/"`, `"foo/a/"`, or `"foo/a/b/c"`.
To expose the wildcard part of the path to the component as a parameter, the following can be done:
```jsx
<Route path="foo/*any" element={<div>{useParams().any}</div>} />
```
:::info
**Note:** The wildcard token must be the last part of the path; `foo/*any/bar` would not create any routes.
:::
### Defining Multiple Paths
Routes can be defined with multiple paths using an array. This feature allows a `Route` component to remain mounted and avoid re-rendering when switching between multiple locations that match any of the predetermined paths.
Using multiple paths can be useful when the same component and state are to be shared between different URLs that serve a similar purpose, such as the following:
```jsx
<Route path={["login", "register"]} component={Login} />
```
## Data Components
Solid Router also supports data components, which are components that fetch and manage data for a specific route. These components offer a declarative and reusable approach to handling data fetching within routes.
To create a data component, you can define a component that fetches and manages data, and then pass it as the `data` prop to the `Route` component.