-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Shallow routing #11307
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Shallow routing #11307
Changes from all commits
Commits
Show all changes
34 commits
Select commit
Hold shift + click to select a range
5a3ed3f
shallow routing
Rich-Harris f93c41c
add types
Rich-Harris cbc33e9
drive-by fix - bad merge
Rich-Harris 48cec22
warn on use of history.pushState and history.replaceState
Rich-Harris eaa539b
regenerate types
Rich-Harris efe9f00
make url the first argument, even though it's optional — this is more…
Rich-Harris b3abca5
tests
Rich-Harris 2cd0d8e
remove state from goto
Rich-Harris 711ee3e
Merge branch 'version-2' into shallow-routing-version-2
Rich-Harris 45d6e87
tidy up
Rich-Harris 1e18fb5
Merge branch 'version-2' into shallow-routing-version-2
benmccann 22489bf
tidy up internal navigate API a bit
Rich-Harris 2900902
more
Rich-Harris 3fcabe2
use current.url for invalidation, not location.href
Rich-Harris 4a88ae6
Merge branch 'shallow-routing-version-2' of github.com:sveltejs/kit i…
Rich-Harris 0d25f49
add docs
Rich-Harris 4135f2a
copy-paste fail
Rich-Harris f4f38f2
on second thoughts
Rich-Harris dc6f168
links
Rich-Harris 0ce07b9
link
Rich-Harris f6b42ba
regenerate types
Rich-Harris 7af49f9
update preloadData docs
Rich-Harris c76c150
fix preloadData docs
Rich-Harris dad37a7
drive-by fix
Rich-Harris 3f31983
Apply suggestions from code review
dummdidumm 89c3161
tweaks
dummdidumm f93df90
changeset, breaking change docs
dummdidumm 54fdf2d
code-golf
dummdidumm f9354c5
this seems unnecessary
dummdidumm edecbe6
mention preloadData
dummdidumm f4152ef
use original replace state
dummdidumm 82d6737
oops
dummdidumm 3a2ff3b
handle SPA case
dummdidumm 5c6e6ae
more involved example - show importing a +page.svelte and correctly h…
Rich-Harris File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@sveltejs/kit": minor | ||
--- | ||
|
||
feat: implement shallow routing |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@sveltejs/kit": major | ||
--- | ||
|
||
breaking: remove state option from goto in favor of shallow routing |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
--- | ||
title: Shallow routing | ||
--- | ||
|
||
As you navigate around a SvelteKit app, you create _history entries_. Clicking the back and forward buttons traverses through this list of entries, re-running any `load` functions and replacing page components as necessary. | ||
|
||
Sometimes, it's useful to create history entries _without_ navigating. For example, you might want to show a modal dialog that the user can dismiss by navigating back. This is particularly valuable on mobile devices, where swipe gestures are often more natural than interacting directly with the UI. In these cases, a modal that is _not_ associated with a history entry can be a source of frustration, as a user may swipe backwards in an attempt to dismiss it and find themselves on the wrong page. | ||
|
||
SvelteKit makes this possible with the [`pushState`](/docs/modules#$app-navigation-pushstate) and [`replaceState`](/docs/modules#$app-navigation-replacestate) functions, which allow you to associate state with a history entry without navigating. For example, to implement a history-driven modal: | ||
|
||
```svelte | ||
<!--- file: +page.svelte ---> | ||
<script> | ||
import { pushState } from '$app/navigation'; | ||
import { page } from '$app/stores'; | ||
import Modal from './Modal.svelte'; | ||
|
||
function showModal() { | ||
pushState('', { | ||
showModal: true | ||
}); | ||
} | ||
</script> | ||
|
||
{#if $page.state.showModal} | ||
<Modal close={() => history.back()} /> | ||
{/if} | ||
``` | ||
|
||
The modal can be dismissed by navigating back (unsetting `$page.state.showModal`) or by interacting with it in a way that causes the `close` callback to run, which will navigate back programmatically. | ||
|
||
## API | ||
|
||
The first argument to `pushState` is the URL, relative to the current URL. To stay on the current URL, use `''`. | ||
|
||
The second argument is the new page state, which can be accessed via the [page store](/docs/modules#$app-stores-page) as `$page.state`. You can make page state type-safe by declaring an [`App.PageState`](/docs/types#app) interface (usually in `src/app.d.ts`). | ||
|
||
To set page state without creating a new history entry, use `replaceState` instead of `pushState`. | ||
|
||
## Loading data for a route | ||
|
||
When shallow routing, you may want to render another `+page.svelte` inside the current page. For example, clicking on a photo thumbnail could pop up the detail view without navigating to the photo page. | ||
|
||
For this to work, you need to load the data that the `+page.svelte` expects. A convenient way to do this is to use [`preloadData`](/docs/modules#$app-navigation-preloaddata) inside the `click` handler of an `<a>` element. If the element (or a parent) uses [`data-sveltekit-preload-data`](/docs/link-options#data-sveltekit-preload-data), the data will have already been requested, and `preloadData` will reuse that request. | ||
|
||
```svelte | ||
<!--- file: src/routes/photos/+page.svelte ---> | ||
<script> | ||
import { preloadData, pushState, goto } from '$app/navigation'; | ||
import Modal from './Modal.svelte'; | ||
import PhotoPage from './[id]/+page.svelte'; | ||
|
||
export let data; | ||
</script> | ||
|
||
{#each data.thumbnails as thumbnail} | ||
<a | ||
href="/photos/{thumbnail.id}" | ||
on:click={async (e) => { | ||
// bail if opening a new tab, or we're on too small a screen | ||
if (e.metaKey || innerWidth < 640) return; | ||
|
||
// prevent navigation | ||
e.preventDefault(); | ||
|
||
const { href } = e.currentTarget; | ||
|
||
// run `load` functions (or rather, get the result of the `load` functions | ||
// that are already running because of `data-sveltekit-preload-data`) | ||
const result = await preloadData(href); | ||
|
||
if (result.type === 'loaded' && result.status === 200) { | ||
pushState(href, { selected: result.data }); | ||
} else { | ||
// something bad happened! try navigating | ||
goto(href); | ||
} | ||
}} | ||
> | ||
<img alt={thumbnail.alt} src={thumbnail.src} /> | ||
</a> | ||
{/each} | ||
|
||
{#if $page.state.selected} | ||
<Modal on:close={() => history.goBack()}> | ||
<!-- pass page data to the +page.svelte component, | ||
just like SvelteKit would on navigation --> | ||
<PhotoPage data={$page.state.selected} /> | ||
</Modal> | ||
{/if} | ||
``` | ||
|
||
## Caveats | ||
|
||
During server-side rendering, `$page.state` is always an empty object. The same is true for the first page the user lands on — if the user reloads the page, state will _not_ be applied until they navigate. | ||
|
||
Shallow routing is a feature that requires JavaScript to work. Be mindful when using it and try to think of sensible fallback behavior in case JavaScript isn't available. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.