Files
Devour/devour_data/docs/routing-and-navigation.json
T
Tomas Dvorak 898a3c303f update
2026-02-24 10:33:59 +01:00

17 lines
17 KiB
JSON

{
"id": "28c7e142c5260178f410ec17",
"source": "solid:signals",
"type": "github-document",
"title": "routing-and-navigation",
"content": "---\ntitle: Routing \u0026 navigation\norder: 4\nuse_cases: \u003e-\n page navigation, url routing, spa routing, dynamic routes, nested layouts,\n route parameters, lazy loading pages\ntags:\n - routing\n - navigation\n - routes\n - spa\n - lazy-loading\n - parameters\n - layouts\nversion: '1.0'\ndescription: \u003e-\n Implement client-side routing in Solid apps with dynamic routes, nested\n layouts, route parameters, and lazy-loaded components.\n---\n\n[Solid Router](/solid-router) simplifies routing in Solid applications to help developers manage navigation and rendering by defining routes using JSX or objects passed via props.\n\n## Getting started\n\n**1. Install the router**\n\nThis package is not included by default.\n\n```package-install\n@solidjs/router\n```\n\n**2. Setup the `\u003cRouter\u003e` component**\n\nStart your application by rendering the [Router](/solid-router/reference/components/router) component.\nThis component will match the URL to display the desired page.\n\n```jsx\nimport { render } from \"solid-js/web\";\nimport { Router } from \"@solidjs/router\";\n\nrender(() =\u003e \u003cRouter /\u003e, document.getElementById(\"root\"));\n```\n\n**3. Provide a root level layout**\n\nThis layout will not update on page change and is the ideal place for top-level navigation and [Context Providers](/concepts/context).\n\n```jsx\nimport { render } from \"solid-js/web\";\nimport { Router } from \"@solidjs/router\";\n\nconst App = (props) =\u003e (\n\t\u003c\u003e\n\t\t\u003ch1\u003eSite Title\u003c/h1\u003e\n\t\t{props.children}\n\t\u003c/\u003e\n);\n\nrender(() =\u003e \u003cRouter root={App} /\u003e, document.getElementById(\"root\"));\n```\n\n**4. Add routes**\n\nEach route is added to the `Router` using the [`Route`](/solid-router/reference/components/route) component.\nHere, you specify a path and a component to render once the user navigates to that path.\n\n```jsx\nimport { render } from \"solid-js/web\";\nimport { Router, Route } from \"@solidjs/router\";\n\nimport Home from \"./pages/Home\";\nimport Users from \"./pages/Users\";\n\nconst App = (props) =\u003e (\n\t\u003c\u003e\n\t\t\u003ch1\u003eSite Title\u003c/h1\u003e\n\t\t{props.children}\n\t\u003c/\u003e\n);\n\nrender(\n\t() =\u003e (\n\t\t\u003cRouter root={App}\u003e\n\t\t\t\u003cRoute path=\"/\" component={Home} /\u003e\n\t\t\t\u003cRoute path=\"/users\" component={Users} /\u003e\n\t\t\u003c/Router\u003e\n\t),\n\tdocument.getElementById(\"root\")\n);\n```\n\n**5. Create a CatchAll route (404 page)**\n\nA catchall route can be used for pages not found at any nested level of the router.\nUsing `*` will retrieve the rest of the path.\nOptionally, you can also add a parameter name.\n\n```jsx\nimport { render } from \"solid-js/web\";\nimport { Router, Route } from \"@solidjs/router\";\n\nimport Home from \"./pages/Home\";\nimport Users from \"./pages/Users\";\nimport NotFound from \"./pages/NotFound\";\n\nconst App = (props) =\u003e (\n\t\u003c\u003e\n\t\t\u003ch1\u003eSite Title\u003c/h1\u003e\n\t\t{props.children}\n\t\u003c/\u003e\n);\n\nrender(\n\t() =\u003e (\n\t\t\u003cRouter root={App}\u003e\n\t\t\t\u003cRoute path=\"/\" component={Home} /\u003e\n\t\t\t\u003cRoute path=\"/users\" component={Users} /\u003e\n\t\t\t\u003cRoute path=\"*paramName\" component={NotFound} /\u003e\n\t\t\u003c/Router\u003e\n\t),\n\tdocument.getElementById(\"root\")\n);\n```\n\n**6. Create links to your routes**\n\nThe [`\u003cA\u003e`](/solid-router/reference/components/a) component provides navigation to an application's routes.\nAlternatively, you can use the [native anchor tag](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a).\nHowever, the `\u003cA\u003e` component provides additional functionality including properties for CSS, `inactiveClass` and `activeClass`.\n\n```jsx\nimport { render } from \"solid-js/web\";\nimport { Router, Route, A } from \"@solidjs/router\";\n\nimport Home from \"./pages/Home\";\nimport Users from \"./pages/Users\";\nimport NotFound from \"./pages/NotFound\";\n\nconst App = (props) =\u003e (\n\t\u003c\u003e\n\t\t\u003cnav\u003e\n\t\t\t\u003cA href=\"/\"\u003eHome\u003c/A\u003e\n\t\t\t\u003cA href=\"/users\"\u003eUsers\u003c/A\u003e\n\t\t\u003c/nav\u003e\n\t\t\u003ch1\u003eSite Title\u003c/h1\u003e\n\t\t{props.children}\n\t\u003c/\u003e\n);\n\nrender(\n\t() =\u003e (\n\t\t\u003cRouter root={App}\u003e\n\t\t\t\u003cRoute path=\"/\" component={Home} /\u003e\n\t\t\t\u003cRoute path=\"/users\" component={Users} /\u003e\n\t\t\t\u003cRoute path=\"*paramName\" component={NotFound} /\u003e\n\t\t\u003c/Router\u003e\n\t),\n\tdocument.getElementById(\"root\")\n);\n```\n\n## Lazy-loading route components\n\nThe [`lazy`](/reference/component-apis/lazy) function postpones the loading of a component until it is navigated to.\n\n```jsx\nimport { lazy } from \"solid-js\";\nimport { render } from \"solid-js/web\";\nimport { Router, Route } from \"@solidjs/router\";\n\nconst Users = lazy(() =\u003e import(\"./pages/Users\"));\nconst Home = lazy(() =\u003e import(\"./pages/Home\"));\n\nconst App = (props) =\u003e (\n\t\u003c\u003e\n\t\t\u003ch1\u003eSite Title\u003c/h1\u003e\n\t\t{props.children}\n\t\u003c/\u003e\n);\n\nrender(\n\t() =\u003e (\n\t\t\u003cRouter root={App}\u003e\n\t\t\t\u003cRoute path=\"/users\" component={Users} /\u003e\n\t\t\t\u003cRoute path=\"/\" component={Home} /\u003e\n\t\t\u003c/Router\u003e\n\t),\n\tdocument.getElementById(\"root\")\n);\n```\n\n## Dynamic routes\n\nIf a path is unknown ahead of time, you can treat part of the path as a flexible parameter.\n\n```jsx\nimport { lazy } from \"solid-js\";\nimport { render } from \"solid-js/web\";\nimport { Router, Route } from \"@solidjs/router\";\n\nconst Users = lazy(() =\u003e import(\"./pages/Users\"));\nconst User = lazy(() =\u003e import(\"./pages/User\"));\nconst Home = lazy(() =\u003e import(\"./pages/Home\"));\n\nrender(\n\t() =\u003e (\n\t\t\u003cRouter\u003e\n\t\t\t\u003cRoute path=\"/users\" component={Users} /\u003e\n\t\t\t\u003cRoute path=\"/users/:id\" component={User} /\u003e\n\t\t\t\u003cRoute path=\"/\" component={Home} /\u003e\n\t\t\u003c/Router\u003e\n\t),\n\tdocument.getElementById(\"root\")\n);\n```\n\nThe colon indicates that `id` can be any string, and as long as the URL fits that pattern, the `\u003cUser\u003e` component will show.\n\nYou can then access that `id` from within a route component with [`useParams`](/solid-router/reference/primitives/use-params).\n\n**Note on animation/transitions**:\nRoutes that share the same path will be treated as the same route.\nIf you want to force re-render, you can wrap your component in a keyed [`\u003cShow\u003e`](/reference/components/show):\n\n```jsx\n\u003cShow when={params.something} keyed\u003e\n \u003cMyComponent\u003e\n\u003c/Show\u003e\n```\n\n### Accessing parameters\n\nIn cases where you may need to access a dynamic route's parameters within your components, the [`useParams`](/solid-router/reference/primitives/use-params) primitive is available.\nOnce the parameters have been accessed using `useParams`, they can be used within your component:\n\n```jsx\nimport { useParams } from \"@solidjs/router\";\n\nconst User = () =\u003e {\n\tconst params = useParams(); // Retrieve the dynamic route parameters\n\t// Now you can access the id parameter as params.id\n\n\treturn (\n\t\t\u003cp\u003e\n\t\t\tThis is the user with the id of \u003ccode\u003e{params.id}\u003c/code\u003e\n\t\t\u003c/p\u003e\n\t);\n};\n```\n\n`useParams` can be especially useful with other Solid primitives, such as [`createResource`](/reference/basic-reactivity/create-resource) and [`createSignal`](/reference/basic-reactivity/create-signal), which can create dynamic behaviors based on the route parameters.\n\n```jsx\nimport { createResource } from \"solid-js\";\nimport { useParams } from \"@solidjs/router\";\n\nasync function fetchUser(id) {\n\tconst response = await fetch(\n\t\t`https://jsonplaceholder.typicode.com/users/${id}`\n\t);\n\treturn response.json();\n}\n\nconst User = () =\u003e {\n\tconst params = useParams();\n\tconst [data] = createResource(() =\u003e params.id, fetchUser); // Pass the id parameter to createResource\n\n\treturn (\n\t\t\u003cdiv\u003e\n\t\t\t\u003cShow when={!data.loading} fallback={\u003cp\u003eLoading...\u003c/p\u003e}\u003e\n\t\t\t\t\u003cdiv\u003e\n\t\t\t\t\t\u003cp\u003eName: {data().name}\u003c/p\u003e\n\t\t\t\t\t\u003cp\u003eEmail: {data().email}\u003c/p\u003e\n\t\t\t\t\t\u003cp\u003ePhone: {data().phone}\u003c/p\u003e\n\t\t\t\t\u003c/div\u003e\n\t\t\t\u003c/Show\u003e\n\t\t\u003c/div\u003e\n\t);\n};\n```\n\nEvery time the `id` parameter changes in this example, the `fetchUser` function is called to fetch the new user data.\n\n### Validating routes\n\nEach path parameter can be validated using a `MatchFilter`.\nInstead of checking for the presence of a parameter, this allows for more complex routing descriptions:\n\n```jsx\nimport { lazy } from \"solid-js\";\nimport { render } from \"solid-js/web\";\nimport { Router, Route, type MatchFilters } from \"@solidjs/router\";\n\nconst User = lazy(() =\u003e import(\"./pages/User\"));\n\nconst filters: MatchFilters = {\n parent: [\"mom\", \"dad\"], // allow enum values\n id: /^\\d+$/, // only allow numbers\n withHtmlExtension: (v: string) =\u003e v.length \u003e 5 \u0026\u0026 v.endsWith(\".html\"), // only `*.html` extensions wanted\n};\n\nrender(() =\u003e (\n \u003cRouter\u003e\n \u003cRoute\n path=\"/users/:parent/:id/:withHtmlExtension\"\n component={User}\n matchFilters={filters}\n /\u003e\n \u003c/Router\u003e\n), document.getElementById(\"root\"));\n```\n\nIn this example, the `matchFilters` prop provides a way to validate the `parent`, `id` and `withHtmlExtension` parameters against the filters defined in `filters`.\nIf the validation fails, the route will not match.\n\nIn this example:\n\n- `/users/mom/123/contact.html` will match,\n- `/users/dad/123/about.html` will match,\n- `/users/aunt/123/contact.html` will **not** match as `:parent` is not 'mom' or 'dad',\n- `/users/mom/me/contact.html` will **not** match as `:id` is not a number,\n- `/users/dad/123/contact` will **not** match as `:withHtmlExtension` is missing `.html`.\n\n### Optional parameters\n\nParameters can be specified as optional by adding a question mark to the end of the parameter name:\n\n```jsx\n// Matches stories and stories/123 but not stories/123/comments\n\u003cRoute path=\"/stories/:id?\" component={Stories} /\u003e\n```\n\n### Wildcard routes\n\nTo match any descendent routes within a given path, you can use the wildcard token (`*`).\nThis can be used to represent any value in that segment of the path.\n\n```jsx\n// Will match any path beginning with foo (eg. foo/, foo/a/, foo/a/b/c)\n\u003cRoute path=\"foo/*\" component={Foo} /\u003e\n```\n\nTo expose the wildcard portion to the component as a parameter, you can name it:\n\n```jsx\n\u003cRoute path=\"foo/*any\" component={Foo} /\u003e\n```\n\nWildcard tokens **must** be the last part of the path; `foo/*any/bar` will not create any routes.\n\n### Multiple paths\n\nThe `Routes` component also supports defining multiple paths using an array.\nThis avoids a route rerendering when switching between two or more locations that it matches:\n\n```jsx\n// Navigating from \"/login\" to \"/register\" will not cause the component to re-render\n\u003cRoute path={[\"login\", \"register\"]} component={Login} /\u003e\n```\n\n## Nested routes\n\nOnly leaf `\u003cRoute\u003e` nodes (the innermost `\u003cRoute\u003e` components) are given a route.\n\n```jsx\n\u003cRoute path=\"/users\" component={Users}\u003e\n\t\u003cRoute path=\"/:id\" component={User} /\u003e\n\u003c/Route\u003e\n```\n\nThe following two route definitions both match the same URL `/users/:id` and render the same component:\n\n```jsx\n\u003cRoute path=\"/users/:id\" component={User} /\u003e\n\n\u003cRoute path=\"/users\"\u003e\n \u003cRoute path=\"/:id\" component={User} /\u003e\n\u003c/Route\u003e\n```\n\nIf you want to make the parent its own route, you have to specify it separately:\n\n```jsx\n\u003cRoute path=\"/users\" component={Users} /\u003e\n\u003cRoute path=\"/users/:id\" component={User} /\u003e\n\n// or\n\n\u003cRoute path=\"/users\"\u003e\n \u003cRoute path=\"/\" component={Users} /\u003e\n \u003cRoute path=\"/:id\" component={User} /\u003e\n\u003c/Route\u003e\n```\n\nYou can also take advantage of nesting by using `props.children` passed to the route component.\n\n```jsx\nfunction PageWrapper(props) {\n\treturn (\n\t\t\u003cdiv\u003e\n\t\t\t\u003ch1\u003e We love our users! \u003c/h1\u003e\n\t\t\t{props.children}\n\t\t\t\u003cA href=\"/\"\u003eBack Home\u003c/A\u003e\n\t\t\u003c/div\u003e\n\t);\n}\n\n\u003cRoute path=\"/users\" component={PageWrapper}\u003e\n\t\u003cRoute path=\"/\" component={Users} /\u003e\n\t\u003cRoute path=\"/:id\" component={User} /\u003e\n\u003c/Route\u003e;\n```\n\nThe routes are still configured the same, however now their components will appear inside the parent component where the `props.children` is declared.\n\nRoutes can also be nested indefinitely.\nThis example will only render the route `/layer1/layer2`, which will be nested in 3 divs.\n\n```jsx\n\u003cRoute\n\tpath=\"/\"\n\tcomponent={(props) =\u003e \u003cdiv\u003eOutermost layer starts here {props.children}\u003c/div\u003e}\n\u003e\n\t\u003cRoute\n\t\tpath=\"layer1\"\n\t\tcomponent={(props) =\u003e \u003cdiv\u003eSecond layer {props.children}\u003c/div\u003e}\n\t\u003e\n\t\t\u003cRoute path=\"layer2\" component={() =\u003e \u003cdiv\u003eInnermost layer\u003c/div\u003e} /\u003e\n\t\u003c/Route\u003e\n\u003c/Route\u003e\n```\n\n## Preload functions\n\nWith preload functions, data fetching is started parallel to loading the route, so it can be used as soon as possible.\nThe preload function prevents this by being called once the Route is loaded, or eagerly if links are hovered.\n\nAs the only argument, the preload function is passed an object that is used to access route information:\n\n```jsx\nimport { lazy } from \"solid-js\";\nimport { Route } from \"@solidjs/router\";\n\nconst User = lazy(() =\u003e import(\"./pages/users/[id].js\"));\n\n// preload function\nfunction preloadUser({ params, location }) {\n\t// do preload\n}\n```\n\nThe preload function is then passed in the `\u003cRoute\u003e` definition:\n\n```jsx\n\u003cRoute path=\"/users/:id\" component={User} preload={preloadUser} /\u003e\n```\n\n---\n\nYou can export preload functions and data wrappers that correspond to routes from a dedicated `[route].data.js` or `[route].data.ts` file.\nThis pattern provides a way to import the data function without loading anything else.\n\n```tsx title=\"src/pages/users/[id].data.js\"\nimport { query } from \"@solidjs/router\";\n\nexport const getUser = query(async (id) =\u003e {\n\treturn (await fetch(`https://swapi.tech/api/people/${id}/`)).json();\n}, \"getUser\");\n\nexport function preloadUser({ params, location, intent }) {\n\treturn getUser(params.id);\n}\n```\n\n`preloadUser` is passed an object which contains `params`, `location` and `intent`.\n\nPlease note that while it is best practice to name these files as `[id].data.js`, you can still name them as `route.data.js`.\n\nThe value of a preload function is passed to the page component when called at any time other than \"preload\".\nThis means you can initialize the page, or use [Data APIs](/solid-router/reference/data-apis/create-async).\n\n:::note\n\tTo prevent a fetch from happening more than once, or to trigger a refetch, you\n\tcan use the [`query` function](/solid-router/reference/data-apis/query).\n:::\n\n```jsx title=\"index.jsx\"\nimport { lazy } from \"solid-js\";\nimport { render } from \"solid-js/web\";\nimport { Router, Route } from \"@solidjs/router\";\nimport { preloadUser } from \"./pages/users/[id].data.js\";\n\nconst Home = lazy(() =\u003e import(\"./pages/Home\"));\nconst User = lazy(() =\u003e import(\"./pages/users/[id]\"));\n\nrender(\n\t() =\u003e (\n\t\t\u003cRouter\u003e\n\t\t\t\u003cRoute path=\"/\" component={Home} /\u003e\n\t\t\t\u003cRoute path=\"/users/:id\" component={User} preload={preloadUser} /\u003e\n\t\t\u003c/Router\u003e\n\t),\n\tdocument.getElementById(\"root\")\n);\n```\n\n`[id].jsx` contains the component that gets rendered.\nWhen you wrap the function within [`createAsync`](/solid-router/reference/data-apis/create-async) with the imported function, it will yield [a signal](/concepts/signals) once the anticipated promise resolves.\n\n```tsx title=\"[id].tsx\"\nimport { createAsync } from \"@solidjs/router\";\nimport { getUser } from \"./[id].data\";\n\nexport default function Users(props) {\n\tconsole.log(\"Users.props\", props);\n\tconst user = createAsync(() =\u003e getUser(props.params.id));\n\treturn (\n\t\t\u003c\u003e\n\t\t\t\u003ch1\u003eUser\u003c/h1\u003e\n\t\t\t\u003cdiv\u003e\n\t\t\t\t\u003cpre\u003e{JSON.stringify(user(), null, 2)}\u003c/pre\u003e\n\t\t\t\u003c/div\u003e\n\t\t\u003c/\u003e\n\t);\n}\n```\n\nTo learn more about routing your Solid applications, visit the [Solid Router documentation](/solid-router).",
"url": "https://github.com/solidjs/solid-docs/blob/HEAD/src/routes/guides/routing-and-navigation.mdx",
"metadata": {
"path": "src/routes/guides/routing-and-navigation.mdx",
"repo": "solidjs/solid-docs",
"repo_url": "https://github.com/solidjs/solid-docs.git",
"size": 14624,
"source_type": "github"
},
"hash": "de150d05836c527b02f32b8f7aaff96d4464fc764494d8f63c728040eb4123fa",
"timestamp": "2026-02-23T11:43:00.187798415+01:00"
}