Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/wicked-plums-count.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/kit': patch
---

[fix] scroll to elements provided via URL hash
17 changes: 10 additions & 7 deletions packages/kit/src/runtime/client/renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -275,12 +275,17 @@ export class Renderer {
this._init(navigation_result);
}

if (opts) {
const { hash, scroll, keepfocus } = opts;
if (!opts?.keepfocus) {
document.body.focus();
}

if (!keepfocus) {
document.body.focus();
}
await 0;

// After `await 0`, the onMount() function in the component executed.
// If there was no manual scrolling happening (checked via pageYOffset),
Comment thread
bluwy marked this conversation as resolved.
Outdated
// continue on our custom scroll handling
if (pageYOffset === 0 && opts) {
const { hash, scroll } = opts;

const deep_linked = hash && document.getElementById(hash.slice(1));
if (scroll) {
Expand All @@ -295,8 +300,6 @@ export class Renderer {
}
}

await 0;

this.loading.promise = null;
this.loading.id = null;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import * as assert from 'uvu/assert';

/**
* A suite of tests that checks that SvelteKit URL anchor is ignored when the
* onMount() lifecycle method contains custom scroll logic.
* @type {import('test').TestMaker}
*/
export default function (test) {
test(
'url-supplied anchor is ignore with onMount() scrolling on direct page load',
Comment thread
bluwy marked this conversation as resolved.
Outdated
'/anchor-with-manual-scroll/anchor#go-to-element',
async ({ page, js }) => {
if (js) {
const p = await page.$('#abcde');
assert.ok(p && (await p.isVisible()));
}
}
);

test(
'url-supplied anchor is ignored with onMount() scrolling on navigation to page',
'/anchor-with-manual-scroll',
async ({ page, clicknav, js }) => {
await clicknav('[href="/anchor-with-manual-scroll/anchor#go-to-element"]');
if (js) {
const p = await page.$('#abcde');
assert.ok(p && (await p.isVisible()));
}
}
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<script>
import { onMount } from 'svelte';

onMount(() => {
document.getElementById('abcde')?.scrollIntoView();
});
</script>

<div>They (don't) see me...</div>
<div style="background-color: peru;">
<p id="go-to-element">The browser scrolls to me</p>
</div>
<p id="abcde">I take precedence</p>

<style>
div {
background-color: hotpink;
height: 180vh;
}
</style>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<h1>Welcome to a test project</h1>
<a href="/anchor-with-manual-scroll/anchor#go-to-element">Anchor demo</a>

<style>
:global(body) {
background-color: tan;
display: flex;
flex-direction: column;
}

a {
display: block;
margin: 20px;
}
</style>
31 changes: 31 additions & 0 deletions packages/kit/test/apps/basics/src/routes/anchor/_tests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import * as assert from 'uvu/assert';

/**
* A suite of tests that checks that SvelteKit URL anchor is respected and the
* element with the anchor ID is scrolled into view.
* @type {import('test').TestMaker}
*/
export default function (test) {
test(
'url-supplied anchor works on direct page load',
'/anchor/anchor#go-to-element',
async ({ page, js }) => {
if (js) {
const p = await page.$('#go-to-element');
assert.ok(p && (await p.isVisible()));
}
}
);

test(
'url-supplied anchor works on navigation to page',
'/anchor',
async ({ page, clicknav, js }) => {
await clicknav('[href="/anchor/anchor#go-to-element"]');
if (js) {
const p = await page.$('#go-to-element');
assert.ok(p && (await p.isVisible()));
}
}
);
}
11 changes: 11 additions & 0 deletions packages/kit/test/apps/basics/src/routes/anchor/anchor.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<div>They (don't) see me...</div>
<div style="background-color: peru;">
<p id="go-to-element">The browser scrolls to me</p>
</div>

<style>
div {
background-color: hotpink;
height: 180vh;
}
</style>
15 changes: 15 additions & 0 deletions packages/kit/test/apps/basics/src/routes/anchor/index.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<h1>Welcome to a test project</h1>
<a href="/anchor/anchor#go-to-element">Anchor demo</a>

<style>
:global(body) {
background-color: tan;
display: flex;
flex-direction: column;
}

a {
display: block;
margin: 20px;
}
</style>
4 changes: 2 additions & 2 deletions packages/kit/test/apps/basics/src/routes/use-action/_tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export default function (test) {
async ({ page, js }) => {
if (js) {
const input = await page.$('#input');
assert.ok(input && input.isVisible);
assert.ok(input && (await input.isVisible()));
assert.ok(await page.$eval('#input', (el) => el === document.activeElement));
}
}
Expand All @@ -25,7 +25,7 @@ export default function (test) {
await clicknav('[href="/use-action/focus-and-scroll"]');
if (js) {
const input = await page.$('#input');
assert.ok(input && input.isVisible);
assert.ok(input && (await input.isVisible()));
assert.ok(await page.$eval('#input', (el) => el === document.activeElement));
}
}
Expand Down