{"id":20463475,"url":"https://github.com/danielsharkov/svelte-router","last_synced_at":"2025-10-14T20:12:19.478Z","repository":{"id":45743236,"uuid":"191619755","full_name":"DanielSharkov/svelte-router","owner":"DanielSharkov","description":"A simple and easy to use svelte router.","archived":false,"fork":false,"pushed_at":"2024-03-22T23:27:49.000Z","size":422,"stargazers_count":13,"open_issues_count":4,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-14T20:11:42.946Z","etag":null,"topics":["router","routing","svelte","typescript"],"latest_commit_sha":null,"homepage":"https://danielsharkov.github.io/svelte-router-examples","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/DanielSharkov.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-06-12T17:54:25.000Z","updated_at":"2024-08-29T01:50:28.000Z","dependencies_parsed_at":"2024-08-04T01:06:39.954Z","dependency_job_id":null,"html_url":"https://github.com/DanielSharkov/svelte-router","commit_stats":{"total_commits":61,"total_committers":4,"mean_commits":15.25,"dds":"0.24590163934426235","last_synced_commit":"dfe23fc45b71c0594014302855b7edbe38ce2aa1"},"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/DanielSharkov/svelte-router","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DanielSharkov%2Fsvelte-router","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DanielSharkov%2Fsvelte-router/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DanielSharkov%2Fsvelte-router/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DanielSharkov%2Fsvelte-router/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/DanielSharkov","download_url":"https://codeload.github.com/DanielSharkov/svelte-router/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DanielSharkov%2Fsvelte-router/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279021008,"owners_count":26086946,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-14T02:00:06.444Z","response_time":60,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["router","routing","svelte","typescript"],"created_at":"2024-11-15T13:11:26.560Z","updated_at":"2025-10-14T20:12:19.456Z","avatar_url":"https://github.com/DanielSharkov.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Simple, fast \u0026 easy to use Svelte Router](https://github.com/DanielSharkov/svelte-router/blob/master/readme-banner.svg)](#)\n\n[![Live Demo](https://img.shields.io/badge/▶-Live%20Demo-2962ff)](https://danielsharkov.github.io/svelte-router-examples)\n[![Examples](https://img.shields.io/badge/🧩-Examples-ff9100)](https://github.com/DanielSharkov/svelte-router-examples)\n[![npm version](https://badge.fury.io/js/@danielsharkov%2Fsvelte-router.svg)](https://badge.fury.io/js/@danielsharkov%2Fsvelte-router)\n![GitHub](https://img.shields.io/github/license/danielsharkov/svelte-router)\n[![Awesome](https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg)](https://github.com/TheComputerM/awesome-svelte#readme)\n\n# 🗂 Index\n\n- [Installation](#-installation)\n- [Initializing a Router Instance](#initializing-a-router-instance)\n- [Fallback Route](#fallback-route)\n- [Route View Component Props](#route-view-component-props)\n- [Route Props](#route-props)\n- [Before-Push Hooks](#before-push-hooks)\n- [Global Before-Push Hook](#global-before-push-hook)\n- [Programmatic History Navigation](#programmatic-history-navigation)\n- [Route Updated Event Listener](#route-updated-event-listener)\n- [RouteLink Component](#routelink-component)\n\t- [RouteLink with Parameters](#routelink-with-parameters)\n- [Svelte Action use:link](#svelte-action-uselink)\n- [Route Transitions](#route-transitions)\n- [Lazy loading](#lazy-loading)\n- [Router Examples](#-router-examples)\n\n\u003cbr\u003e\n\n# 🧗‍♀️ Getting Started\n\n## 💿 Installation\n\nDepending on your package manager just:\n\n**pnpm**\u003cbr\u003e\n`pnpm add -D @danielsharkov/svelte-router`\n\n**yarn**\u003cbr\u003e\n`yarn add --dev @danielsharkov/svelte-router`\n\n**npm**\u003cbr\u003e\n`npm i -D @danielsharkov/svelte-router`\n\nAnd done 😁 🎉\n\n\u003cbr\u003e\n\n## Initializing a Router Instance\n\nInitialize a new router with the configuration in `src/router.ts` or where\never you like, maybe even inside `App.svelte` as a module - it's up to you.\n\n```ts\nimport SvelteRouter from '@danielsharkov/svelte-router'\nimport ViewHome from './views/Home.svelte'\nimport ViewUser from './views/User.svelte'\nimport ViewAlbum from './views/Album.svelte'\n\nexport default new SvelteRouter({\n\twindow: window,\n\tscrollingElement: window.document.scrollingElement,\n\tbasePath: '/persistent/path',\n\troutes: {\n\t\t'home': {\n\t\t\tpath: '/',\n\t\t\tcomponent: ViewHome,\n\t\t},\n\t\t'users.user': {\n\t\t\t// paths must always begin with a slash\n\t\t\t// and may take parameters prefixed by a colon\n\t\t\tpath: '/users/:uid',\n\t\t\tcomponent: ViewUser,\n\t\t},\n\t\t'user.album': {\n\t\t\t// paths may take multiple parameters\n\t\t\tpath: '/users/:uid/albums/:aid',\n\t\t\tcomponent: ViewAlbum,\n\t\t},\n\t},\n})\n```\n\n* `window` should usually be assigned the [browser object model](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model)\nbut can also be used for testing and debugging purposes.\n\n* `scrollingElement` should usually be assigned the [Document.scrollingElement](https://developer.mozilla.org/en-US/docs/Web/API/document/scrollingElement),\nwhich is the usual scrollable viewport. But if your viewport differs you may\nthen provid it your needed `Element`. When no `scrollableElement` is provided\nthen the router won't save and restore scroll state by the history.\n\n* `basePath` is an optional field which has the same principle as the HTML\n`\u003cBase\u003e` tag. It acts like a prefix to the paths. It's useful in cases like\nhosting on GitHub Pages, where the base URL is always `https://\u003cusername\u003e.github.io/\u003crepo-name\u003e`\nand the base path therefor always is `/\u003crepo-name\u003e`.\n\n* a route name is required to be unique and is allowed to contain\n`a-z`, `A-Z`, `0-9`, `-`, `_` and `.`\n\n* static routes will always be preferred to their parameterized counterparts.\nThis means `user/a/albums` will be preferred to `/user/:id/albums` if the URL\nmatches the static route.\n\nThen use the `Viewport` as the actual visual router in your `App.svelte`\npassing it your created router instance:\n\n```svelte\n\u003cscript lang='ts'\u003e\nimport Viewport from '@danielsharkov/svelte-router/Viewport'\nimport router from './router'\n\u003c/script\u003e\n\n\u003cnav\u003e\n\t\u003cbutton on:click={()=\u003e router.push('home')}\u003e\n\t\tHome\n\t\u003c/button\u003e\n\t\u003cbutton on:click={()=\u003e router.push('users.user', {uid: 'paul'})}\u003e\n\t\tPaul\n\t\u003c/button\u003e\n\t\u003cbutton on:click={()=\u003e router.push('user.album', {uid: 'alex', aid: 'sumer-2016'})}\u003e\n\t\tBob's Album\n\t\u003c/button\u003e\n\u003c/nav\u003e\n\n\u003cViewport {router}/\u003e\n```\n\n\n\u003cbr\u003e\n\n--------------------------------------------------------------------------------\n\u003cbr\u003e\n\n\n# Fallback Route\n\n```ts\nimport SvelteRouter from '@danielsharkov/svelte-router'\nimport ViewHome from './views/Home.svelte'\nimport ViewNotFound from './views/NotFound.svelte'\n\nexport default new SvelteRouter({\n\twindow,\n\troutes: {\n\t\t'home': {\n\t\t\tpath: '/',\n\t\t\tcomponent: ViewHome,\n\t\t},\n\t\t'404': {\n\t\t\tpath: '/404',\n\t\t\tcomponent: ViewNotFound,\n\t\t},\n\t},\n\tfallback: {\n\t\tname: '404',\n\t\treplace: false, // true by default\n\t},\n})\n```\n\n`fallback` is optional and defines the route the router should fallback to in\ncase the user navigates to an inexistent URL. If `replace` is `false` then the\nfallback will push the route into the browser history and change the URL,\notherwise it'll just display the fallback route in the router viewport without\naffecting the browser history. `replace` is `true` by default.\n\n\n\u003cbr\u003e\n\n--------------------------------------------------------------------------------\n\u003cbr\u003e\n\n\n# Route View Component Props\n\nThe route view components always get the props `router`, `params`, `urlQuery`\nand `props`.\n\n```svelte\n\u003cscript lang='ts'\u003e\nexport let router\n// router: is the SvelteRouter instance you provided to \u003cViewport\u003e\n\nexport let params\n// params: is either undefined or the parameters you defined\n// in the path template for this route in the router config.\n\nexport let urlQuery\n// urlQuery: is either undefined or a key:value object depending whether\n// the URL has any query parameters.\n\nexport let props\n// props: is either undefined or the defined props for this route\n// in the router config.\n\n// We assume that the route parameters always exist, because we defined\n// them parameters in the path template for this route in the router config -\n// and they do always exist, because the router won't route on a route\n// missing its parameters.\n// You can may access these values without worry of trying to access an\n// undefined property.\nconsole.log(params.someParam)\n\n// Same follows for props, they are hard-coded and therefore always defined.\nconsole.log(props.nav.title)\n\n// Only the urlQuery keys must be checked first, because there's is no\n// definition for the URL query.\nif (urlQuery.search) console.log(search)\n\u003c/script\u003e\n\n\u003c!-- Here your Layout \u0026 Styles ... --\u003e\n```\n\n\n\u003cbr\u003e\n\n--------------------------------------------------------------------------------\n\u003cbr\u003e\n\n\n# Route Props\n\nRoutes can be assigned arbitrary props which are then available in the view\ncomponent:\n\n\u003csub\u003e**router.ts**\u003c/sub\u003e\n```ts\nimport SvelteRouter from '@danielsharkov/svelte-router'\nimport ViewHome from './views/Home.svelte'\nimport ViewAbout from './views/About.svelte'\n\nexport default new SvelteRouter({\n\twindow,\n\troutes: {\n\t\t'root': {\n\t\t\tpath: '/',\n\t\t},\n\t\t'home': {\n\t\t\tpath: '/home',\n\t\t\tcomponent: ViewHome,\n\t\t\tprops: {\n\t\t\t\tnav: {\n\t\t\t\t\ttitle: 'Home',\n\t\t\t\t\ticon: 'fas fa-home',\n\t\t\t\t},\n\t\t\t\tpicture: 'https://sample.url/picture.jpg',\n\t\t\t},\n\t\t},\n\t\t'about': {\n\t\t\tpath: '/about',\n\t\t\tcomponent: ViewAbout,\n\t\t\tprops: {\n\t\t\t\tnav: {\n\t\t\t\t\ttitle: 'About me',\n\t\t\t\t\ticon: 'fas fa-address-card',\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n})\n```\n\n\u003csub\u003e**views/Home.svelte**\u003c/sub\u003e\n\n```svelte\n\u003cscript lang='ts'\u003e\nexport let props\n\u003c/script\u003e\n\n\u003c!-- We assume that these props always exist,\nbecause we hard-coded them into the router --\u003e\n\u003ch1\u003e{props.nav.title}\u003c/h1\u003e\n\u003cimg src={props.picture} alt='Some beautiful picture'\u003e\n```\n\n\u003csub\u003e**App.svelte**\u003c/sub\u003e\n\n```svelte\n\u003cscript lang='ts'\u003e\nimport router from './router'\n\u003c/script\u003e\n\n\u003cnav\u003e\n\t{#each $router.routes as route}\n\t\t{#if route.props?.nav}\n\t\t\t\u003cbutton on:click={router.push(route.name)}\u003e\n\t\t\t\t\u003ci class='{route.props.nav.icon}'/\u003e\n\t\t\t\t\u003cspan\u003e{route.props.nav.title}\u003c/span\u003e\n\t\t\t\u003c/button\u003e\n\t\t{/if}\n\t{/each}\n\u003c/nav\u003e\n```\n\n\n\u003cbr\u003e\n\n--------------------------------------------------------------------------------\n\u003cbr\u003e\n\n\n# Before-Push Hooks\n\nThe `beforePush` hooks are promises which are executed before a route is pushed\nto the history. The passed function receives an object containing the current\n`location`, the `pendingRoute` (which the router is about to navigate to) and both\nthe `resolver` and `rejector`. A hook must either resolve (approve) the pending\nroute otherwise to reject it by passing an another route, or even\nnothing (`undefined`) to cancel routing. It can be used for specifying redirect behavior or\nanything else that should be done before a push.\n\nYou may use the `$router.isLoading` property to determine whether the router is\nloading a new route and resolving before push hooks, which may be asynchronous.\n\n| ⚠ Warning ⚠ |\n|:--|\nBe sure to always either resolve or reject a hook, otherwise it will **dead-lock** your router.\n\nSimple example of using a hook:\n\n```svelte\n\u003cscript\u003e\nimport {onDestroy} from 'svelte'\nimport router from './router'\n\nconst testHookID = 'test-hook'\nconst removeBeforePushHook = router.addBeforePushHook(\n\ttestHookID,\n\t({location, pendingRoute, resolve, reject})=\u003e {\n\t\tif (pendingRoute.name === '/very/secret/path') {\n\t\t\treject()\n\t\t}\n\t\tresolve()\n\t}\n)\n\nonDestroy(()=\u003e {\n\tremoveBeforePushHook()\n\t// or\n\t// router.removeBeforePush(testHookID)\n})\n\u003c/script\u003e\n```\n\n\n\u003cbr\u003e\n\n--------------------------------------------------------------------------------\n\u003cbr\u003e\n\n\n# Global Before-Push Hook\n\nThe global before push hook is a persistent hook, which can't be removed.\nIt's defined right in the router config.\nHere's a simple example:\n\n```ts\nimport SvelteRouter from '@danielsharkov/svelte-router'\nimport {get as get$} from 'svelte/store'\nimport {isValidUserSession} from 'user_session'\n// isValidSession could be any of your implementations - in this example it is\n// just a derived store returning false or true\n\nimport ViewLogin from './views/Login.svelte'\nimport ViewHome from './views/Home.svelte'\nimport ViewUser from './views/User.svelte'\n\nexport default new SvelteRouter({\n\twindow,\n\troutes: {\n\t\t'root': {\n\t\t\tpath: '/',\n\t\t},\n\t\t'login': {\n\t\t\tpath: '/login',\n\t\t\tcomponent: ViewLogin,\n\t\t},\n\t\t'home': {\n\t\t\tpath: '/home',\n\t\t\tcomponent: ViewHome,\n\t\t},\n\t\t'user': {\n\t\t\tpath: '/user/:uid',\n\t\t\tcomponent: ViewUser,\n\t\t},\n\t\t'very-secret': {\n\t\t\tpath: '/treasure',\n\t\t}\n\t},\n\tbeforePush({pendingRoute, location, resolve, reject}) {\n\t\tif (!get$(isValidUserSession)) {\n\t\t\treject({name: 'login'})\n\t\t} else if (pendingRoute.name === 'login') {\n\t\t\treject()\n\t\t}\n\n\t\tswitch (pendingRoute) {\n\t\tcase 'root':\n\t\t\treject({name: 'home'})\n\t\t\tbreak\n\t\tcase 'user':\n\t\t\tif (params.uid === 'a') {\n\t\t\t\treject({\n\t\t\t\t\tname: pendingRoute.name,\n\t\t\t\t\tparams: {uid: 'b'},\n\t\t\t\t})\n\t\t\t}\n\t\t\tbreak\n\t\tcase 'very-secret':\n\t\t\treject()\n\t\t}\n\t\tresolve()\n\t},\n})\n```\n\n\n\u003cbr\u003e\n\n--------------------------------------------------------------------------------\n\u003cbr\u003e\n\n\n# Programmatic History Navigation\n\nTo programmatically go back or forward in history just use the [browser history API](https://developer.mozilla.org/en-US/docs/Web/API/History_API) or the built-in aliases:\n\n\n```svelte\n\u003cscript lang='ts'\u003e\nimport type SvelteRouter from '@danielsharkov/svelte-router'\nexport let router: SvelteRouter\n\u003c/script\u003e\n\n\u003cbutton on:click={router.back}\u003eBack\u003c/button\u003e\n\u003cbutton on:click={router.forward}\u003eForward\u003c/button\u003e\n```\n\nTo navigate to a new route use the built-in `push` API of the router, which\nrequires the route name as the first parameter and if needed a `key:value` object\nwith the parameter values:\n\n```svelte\n\u003cscript lang='ts'\u003e\nimport type SvelteRouter from '@danielsharkov/svelte-router'\nexport let router: SvelteRouter\n\u003c/script\u003e\n\n\u003cbutton on:click={()=\u003e router.push('home')}\u003e\n\tHome\n\u003c/button\u003e\n\u003cbutton on:click={()=\u003e router.push('user', {uid: 'ndkh2oj2'})}\u003e\n\tDennis\n\u003c/button\u003e\n\u003cbutton on:click={()=\u003e router.push('user', {uid: 'sz92fnkk'})}\u003e\n\tErik\n\u003c/button\u003e\n```\n\n\n\u003cbr\u003e\n\n--------------------------------------------------------------------------------\n\u003cbr\u003e\n\n\n# Route Updated Event Listener\n\nThe `routeUpdated` event listener if fired right after the route has been updated.\nThe payload in the event is the current location.\n\n```svelte\n\u003cscript lang='ts'\u003e\nexport let params;\n\nfunction routeUpdated(event) {\n\tconsole.log('Route params changed!', event.detail.params)\n\tconsole.log(parms, 'is equal to the event payload')\n}\n\u003c/script\u003e\n\n\u003csvelte:window on:routeUpdated={routeUpdated}/\u003e\n```\n\n\n\u003cbr\u003e\n\n--------------------------------------------------------------------------------\n\u003cbr\u003e\n\n\n# RouteLink Component\nA `\u003cRouteLink\u003e` can only be used inside a `\u003cViewport\u003e` instance or by\npassing it the router instance. You may pass HTML tag attributes like `class`,\n`id` and etc. directly to the component - as you'll see in the example below.\n\n\u003csub\u003e**router.ts**\u003c/sub\u003e\n```ts\nimport SvelteRouter from '@danielsharkov/svelte-router'\nimport ViewHome from './views/Home.svelte'\nimport ViewAbout from './views/About.svelte'\nimport ViewUser from './views/User.svelte'\n\nexport default new SvelteRouter({\n\twindow,\n\troutes: {\n\t\t'root': {\n\t\t\tpath: '/',\n\t\t},\n\t\t'home': {\n\t\t\tpath: '/home',\n\t\t\tcomponent: ViewHome,\n\t\t\tprops: {\n\t\t\t\tnav: {\n\t\t\t\t\ttitle: 'Home',\n\t\t\t\t\ticon: 'fas fa-home',\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t'about': {\n\t\t\tpath: '/about',\n\t\t\tcomponent: ViewAbout,\n\t\t\tprops: {\n\t\t\t\tnav: {\n\t\t\t\t\ttitle: 'About me',\n\t\t\t\t\ticon: 'fas fa-address-card',\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t'user': {\n\t\t\tpath: '/about/:userName/:userNumber',\n\t\t\tcomponent: ViewUser,\n\t\t},\n\t},\n})\n```\n\n\u003csub\u003e**components/Nav.svelte**\u003c/sub\u003e\n```svelte\n\u003cscript\u003e\nimport RouteLink from '@danielsharkov/svelte-router/RouteLink'\nimport router from '../router'\n\u003c/script\u003e\n\n\u003cnav\u003e\n\t{#each $router.routes as route}\n\t\t{#if route.props?.nav}\n\t\t\t\u003cRouteLink to={route.name} class='nav-btn'\u003e\n\t\t\t\t\u003ci class=\"{route.props.nav.icon}\"/\u003e\n\t\t\t\t\u003cspan\u003e{route.props.nav.title}\u003c/span\u003e\n\t\t\t\u003c/RouteLink\u003e\n\t\t{/if}\n\t{/each}\n\u003c/nav\u003e\n\n\u003c!-- The only disadvantage is that you have to define the styles globally --\u003e\n\u003cstyle\u003e\n:global(.nav-btn) {\n\tcolor: #ff3e00;\n}\n\u003c/style\u003e\n```\n\n#### RouteLink with parameters\n\n```svelte\n\u003cRouteLink to='user' params={{userName: 'john_doe', userNumber: 0397}}\u003e\n\tI'm a router link\n\u003c/RouteLink\u003e\n```\n\n\n\u003cbr\u003e\n\n--------------------------------------------------------------------------------\n\u003cbr\u003e\n\n\n# Svelte Action `use:link`\nThe use action can only be used inside a `\u003cViewport\u003e` instance or by\npassing it the router instance. When you're using it inside a `\u003cViewport\u003e`,\nthen leave the parameter `router` blank.\n\n##### Inside a `\u003cViewport\u003e`\n```svelte\n\u003cscript\u003e\nimport {link} from '@danielsharkov/svelte-router'\n\u003c/script\u003e\n\n\u003ca href='/home' use:link class:active={$router.location === 'home'}\u003e\n\tHome\n\u003c/a\u003e\n\u003ca href='/about' use:link class:active={$router.location === 'about'}\u003e\n\tAbout\n\u003c/a\u003e\n\u003ca href='/user/lauren/8953' use:link class:active={$router.location === 'home'}\u003e\n\tLauren#8953 \u003c!-- matches /user/:userName/:userNumber --\u003e\n\u003c/a\u003e\n\n\u003cstyle\u003e\na.active {\n\tcolor: #ff3e00;\n}\n\u003c/style\u003e\n```\n\n##### Outside a `\u003cViewport\u003e`\n```svelte\n\u003cscript\u003e\nimport {link} from '@danielsharkov/svelte-router'\nimport Viewport from '@danielsharkov/svelte-router/Viewport'\nimport router from './router'\n\u003c/script\u003e\n\n\u003ca href='/home' use:link={router}\u003eHome\u003c/a\u003e\n\u003ca href='/about' use:link={router}\u003eAbout\u003c/a\u003e\n\u003ca href='/user/lauren/8953' use:link={router}\u003eLauren\u003c/a\u003e\n\n\u003cViewport {router}/\u003e\n```\n\n\n\u003cbr\u003e\n\n--------------------------------------------------------------------------------\n\u003cbr\u003e\n\n\n# Route Transitions\nRoute transitions can't be just applied and used on a route easily. If you\nwould just add some transitions into the route component and navigate through\nthe routes, it will show unexpected behavior (\n\tsee Svelte Issues:\n\t[#6779](https://github.com/sveltejs/svelte/issues/6779),\n\t[#6763](https://github.com/sveltejs/svelte/issues/6763),\n\t[and even including my simple REPL](https://svelte.dev/repl/a5122281148c4c458f40e317fc4be11e?version=3.44.2)\n).\n\n**But! Dirty hacks to the rescue:** 😎💡\n\nTo tell the viewport that a route has a transition you must dispatch the event\n`hasOutro` inside the `onMount` handler. Now that the viewport is aware of the\noutro transition, it's going to await the route to finish its transition,\nbefore switching to the next route.\nNow that the router is awaiting the outro, at the end of the transition we have\nto tell the viewport that it may switch further to the next route.\nThis is done by dispatching the another event called `outroDone`.\nThat's the trick!\n\n| ℹ Info |\n|:--|\nAny mistaken dispatched event `outroDone` will be ignored by the viewport, as it only listens for the event after the routers location has changed. Meaning you may just dispatch this event on every outro transition without worring.\n\n| ℹ Info |\n|:--|\nInside the route component be sure to call the `outroDone` event on the longest outro transition on any element inside the component, as they have to finish as well. For better understanding see the second example below 👇\n\n| ⚠ Warning ⚠ |\n|:--|\nBe sure to fire the event `outroDone` after telling the viewport to await the outro transition, otherwise the viewport will wait a indefinitely.\n\n```svelte\n\u003cscript lang='ts'\u003e\nimport {onMount, createEventDispatcher} from 'svelte'\nimport {fade} from 'svelte/transition'\nconst dispatch = createEventDispatcher()\n\nonMount(()=\u003e {\n\tdispatch('hasOutro')\n})\n\u003c/script\u003e\n\n\u003cdiv class='page'\ntransition:fade={{duration: 400}}\non:outroend={()=\u003e dispatch('outroDone')}\u003e\n\t\u003ch1\u003eSome content\u003c/h1\u003e\n\n\t\u003cp\u003eLorem Impsum...\u003c/p\u003e\n\u003c/div\u003e\n```\n\n##### A route containing a child transition\n```svelte\n\u003cscript lang='ts'\u003e\nimport {onMount, createEventDispatcher} from 'svelte'\nimport {fade, fly} from 'svelte/transition'\nconst dispatch = createEventDispatcher()\n\nonMount(()=\u003e {\n\tdispatch('hasOutro')\n})\n\nconst custom =()=\u003e ({\n\tduration: 1000,\n\tcss: (t)=\u003e (\n\t\t`opacity: ${t};` +\n\t\t`transform: rotate(${360 - 360 * t}deg);`\n\t)\n})\n\u003c/script\u003e\n\n\u003c!-- You may delay the actual route transition, otherwise it will already\nfade out and the user will see a blank screen, where it's actually is still\nprocessing a child outro. I set it to 600ms, because 1000ms of the longest\nchild transition (the heading) minus the 400ms route transition is a delay of 600ms. --\u003e\n\n\u003cdiv class='page'\ntransition:fade={{duration: 400, delay: 600}}\non:outroend={()=\u003e dispatch('outroDone')}\u003e\n\t\u003ch1 transition:custom\u003e\n\t\tSome content\n\t\u003c/h1\u003e\n\n\t\u003cp style='display: inline-block;' transition:fly={{duration: 700}}\u003e\n\t\tLorem Impsum...\n\t\u003c/p\u003e\n\u003c/div\u003e\n```\n\n\n\u003cbr\u003e\n\n--------------------------------------------------------------------------------\n\u003cbr\u003e\n\n\n# 🥱 Lazy loading\nTo lazy load components you would need to set the field `lazyComponent` instead\nof `component`. The router will panic when using both, as it makes no sense.\nYou may even provide a `loading` and `fallback` component, which act like a\nregular route component, meaning they [can be smoothly transitioned](#route-transitions) as well.\n\n```ts\nimport SvelteRouter from '@danielsharkov/svelte-router'\nimport RouteLoading from './components/RouteLoading.svelte'\nimport RouteLoadFailedFallback from './components/RouteLoadFailedFallback.svelte'\n\nimport ViewHome from './views/Home.svelte'\nimport ViewNotFound from './views/NotFound.svelte'\n\nexport default new SvelteRouter({\n\twindow: window,\n\tscrollingElement: window.document.scrollingElement,\n\troutes: {\n\t\t'home': {\n\t\t\tpath: '/',\n\t\t\tcomponent: ViewHome,\n\t\t},\n\t\t'users.user': {\n\t\t\tpath: '/users/:uid',\n\t\t\tlazyComponent: {\n\t\t\t\t// lazy load and show this component:\n\t\t\t\tcomponent: async ()=\u003e (await import('./views/User.svelte')).default,\n\t\t\t\t// when the actual route component is loading show:\n\t\t\t\tloading: RouteLoading,\n\t\t\t\t// in case it fails loading the component show:\n\t\t\t\tfallback: RouteLoadFailedFallback,\n\t\t\t},\n\t\t},\n\t\t'user.album': {\n\t\t\tpath: '/users/:uid/albums/:aid',\n\t\t\tlazyComponent: {\n\t\t\t\tcomponent: async ()=\u003e (await import('./views/Album.svelte')).default,\n\t\t\t\tloading: RouteLoading,\n\t\t\t\tfallback: RouteLoadFailedFallback,\n\t\t\t},\n\t\t},\n\t\t// this route below will never load, it would always first show the\n\t\t// loading and then the fallback component after 2 seconds\n\t\t'will-never-load': {\n\t\t\tpath: '/users/:uid/albums/:aid',\n\t\t\tlazyComponent: {\n\t\t\t\tcomponent: async ()=\u003e new Promise((_, reject)=\u003e setTimeout(reject, 2e3)),\n\t\t\t\tloading: RouteLoading,\n\t\t\t\tfallback: RouteLoadFailedFallback,\n\t\t\t},\n\t\t},\n\t\t'404': {\n\t\t\tpath: '/404',\n\t\t\t// This component mustn't be lazy loaded, as it makes no sense.\n\t\t\t// Still though it's possible.\n\t\t\tcomponent: ViewNotFound,\n\t\t},\n\t},\n\tfallback: {name: '404'},\n})\n```\n\n\n\u003cbr\u003e\n\n--------------------------------------------------------------------------------\n\u003cbr\u003e\n\n\n# 🧩 Router Examples\nYou can find full router examples in [danielsharkov/svelte-router-examples](https://github.com/DanielSharkov/svelte-router-examples)\n\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e\n\n\n\n# ✨ Thanks for contribution goes to:\n[@romshark](https://github.com/romshark)\n[@madebyfabian](https://github.com/madebyfabian)\n\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e\n\n\n\n# ⚖️ License\nSvelte Router is a open source software [licensed as MIT](LICENSE).\n\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e\n\n\n\n# ⚖️ Additional notices\nYou may feel free to use the [Logo](https://github.com/DanielSharkov/svelte-router/blob/master/logo.svg), [Animated Logo](https://github.com/DanielSharkov/svelte-router/blob/master/logo-animated.svg) and [Banner](https://github.com/DanielSharkov/svelte-router/blob/master/readme-banner.svg) for non-commercial usage only, but first please ask me kindly. Contact me by email on `scharktv[at]gmail.com`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanielsharkov%2Fsvelte-router","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdanielsharkov%2Fsvelte-router","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanielsharkov%2Fsvelte-router/lists"}