Skip to content

fix: support app-owned scroll containers - #16427

Open
scarab-systems wants to merge 5 commits into
sveltejs:version-3from
scarab-systems:scarab-systems/sveltekit-2733-scroll-container
Open

fix: support app-owned scroll containers#16427
scarab-systems wants to merge 5 commits into
sveltejs:version-3from
scarab-systems:scarab-systems/sveltekit-2733-scroll-container

Conversation

@scarab-systems

@scarab-systems scarab-systems commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

closes #2733

This takes a focused pass at the scroll-container part of this issue. I used Scarab boundary diagnostics to look for where the reported behavior crossed from app layout into router-owned scroll management, then used that as the repair boundary.

The boundary I found was that SvelteKit's router captures/restores scroll state from the window and applies navigation scrolls with window.scrollTo(...), while a common app-shell layout keeps the document fixed and scrolls an inner element instead. In that layout, SvelteKit can successfully navigate but still preserve the old visual scroll position because it is reading and writing the wrong scroll owner.

This PR adds an explicit data-sveltekit-scroll-container opt-in for that case. When present, SvelteKit reads/restores that element's scrollLeft/scrollTop; otherwise the existing window behavior is unchanged.

I looked through the previous attempts/discussion before shaping this:

The regression fixture uses a fixed app shell with an inner <main data-sveltekit-scroll-container>. It verifies both forward navigation to the top and back-button scroll restoration. It also includes a data-sveltekit-scroll-container="false" wrapper so the selected scroll owner is explicit and test-protected.

Happy to adjust the attribute name, docs location, or shape of the opt-in if maintainers prefer a different public API.


Please don't delete this checklist! Before submitting the PR, please make sure you do the following:

  • It's really useful if your PR references an issue where it is discussed ahead of time. In many cases, features are absent for a reason. For large changes, please create an RFC: https://github.com/sveltejs/rfcs
  • This message body should clearly illustrate what problems it solves.
  • Ideally, include a test that fails without this PR but passes with it.

Tests

  • Run the tests with pnpm test and lint the project with pnpm lint and pnpm check

Checked in an isolated repo workspace:

  • pnpm run format
  • pnpm -F @sveltejs/kit prepublishOnly
  • NODE_OPTIONS=--max-old-space-size=4096 pnpm run lint
  • NODE_OPTIONS=--max-old-space-size=4096 pnpm run check
  • NODE_OPTIONS=--max-old-space-size=4096 pnpm -F @sveltejs/kit test:unit
  • pnpm --dir packages/kit/test/apps/basics test:cross-platform:dev --grep "app-owned container" --project=chromium-dev
  • pnpm --dir packages/kit/test/apps/basics test:cross-platform:dev --grep "Scrolling" --project=chromium-dev
  • pnpm --dir packages/kit/test/apps/basics test:cross-platform:build --grep "app-owned container" --project=chromium-build

Changesets

  • If your PR makes a change that should be noted in one or more packages' changelogs, generate a changeset by running pnpm changeset and following the prompts. Changesets that add features should be minor and those that fix bugs should be patch. Please prefix changeset messages with fix:, feat:, or chore:.

Edits

  • Please ensure that 'Allow edits from maintainers' is checked. PRs without this option may be closed.

Disclosure: This PR was prepared with AI assistance under human direction and review.

@pkg-svelte-dev

pkg-svelte-dev Bot commented Jul 19, 2026

Copy link
Copy Markdown

Install the latest version of @sveltejs/kit from 4a4ea3a:

pnpm add https://pkg.svelte.dev/@sveltejs/kit/c/4a4ea3aa581d7b228b9c9c614ca9bf34898178f4

Open in pkg.svelte.dev: https://pkg.svelte.dev/repos/kit/pr/16427

Note

This PR is from a fork. A maintainer must approve approve each commit before it can be built and installed.

@changeset-bot

changeset-bot Bot commented Jul 19, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 4a4ea3a

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@sveltejs/kit Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@scarab-systems
scarab-systems force-pushed the scarab-systems/sveltekit-2733-scroll-container branch from dfe5840 to 90d7f34 Compare July 24, 2026 21:14
@scarab-systems
scarab-systems force-pushed the scarab-systems/sveltekit-2733-scroll-container branch from 90d7f34 to 3ecd821 Compare July 24, 2026 21:18
Resolve the client scroll restoration conflict by keeping the current history metadata flow and routing restored/top scroll operations through the scroll helper.

Verification: pnpm install --frozen-lockfile with Node 22.23.1; focused basics cross-platform scroll-container tests passed in dev and build modes; pnpm -F @sveltejs/kit test:unit passed; pnpm -F @sveltejs/kit prepublishOnly passed; git diff --check passed.
Resolve the shallow popstate scroll restoration conflict by keeping upstream navigation snapshot capture/restore and routing restored scroll positions through the scroll-container-aware helper.\n\nVerification:\n- pnpm install --frozen-lockfile with Node v22.23.1 and pnpm v11.21.0\n- pnpm run test:cross-platform:dev -- --grep "app-owned container" (argument landed after an extra --, so the full basics cross-platform dev suite ran: 283 passed, 103 skipped)\n- pnpm run test:cross-platform:build --grep "app-owned container" (2 passed, 2 skipped)\n- pnpm -F @sveltejs/kit test:unit\n- pnpm -F @sveltejs/kit prepublishOnly\n- pnpm -F @sveltejs/kit lint\n- pnpm -F @sveltejs/kit check\n- git diff --cached --check upstream/version-3
Resolve the client popstate scroll restoration conflict by keeping upstream's current history index flow while routing restored scroll positions through the scroll-container-aware helper.

Verification: npm exec --yes pnpm@12.2.1 -- pnpm install --frozen-lockfile; npm exec --yes pnpm@12.2.1 -- pnpm --dir packages/kit/test/apps/basics test:cross-platform:dev --grep "app-owned container" --project=chromium-dev; npm exec --yes pnpm@12.2.1 -- pnpm --dir packages/kit/test/apps/basics test:cross-platform:build --grep "app-owned container" --project=chromium-build; npm exec --yes pnpm@12.2.1 -- pnpm -F @sveltejs/kit test:unit; npm exec --yes pnpm@12.2.1 -- pnpm -F @sveltejs/kit prepublishOnly; npm exec --yes pnpm@12.2.1 -- pnpm -F @sveltejs/kit lint; npm exec --yes pnpm@12.2.1 -- pnpm -F @sveltejs/kit check; git diff --check.
Signed-off-by: ScarabSystems <scarab.systems@yahoo.com>
@coderabbitai

coderabbitai Bot commented Sep 5, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: QUIET

Plan: Advanced

Run ID: 2193ec4e-7ac3-4eb1-b5aa-36385a7b891c

📥 Commits

Reviewing files that changed from the base of the PR and between c47be02 and 4a4ea3a.

📒 Files selected for processing (9)
  • .changeset/smart-lamps-dance.md
  • documentation/docs/30-advanced/30-link-options.md
  • packages/kit/src/core/sync/write_app_types.js
  • packages/kit/src/runtime/client/client.js
  • packages/kit/src/runtime/client/utils.js
  • packages/kit/test/apps/basics/src/routes/scroll/custom-container/+layout.svelte
  • packages/kit/test/apps/basics/src/routes/scroll/custom-container/a/+page.svelte
  • packages/kit/test/apps/basics/src/routes/scroll/custom-container/b/+page.svelte
  • packages/kit/test/apps/basics/test/cross-platform/client.test.js
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • sveltejs/vite-plugin-svelte (manual)
  • vitejs/vite (manual)
  • sveltejs/svelte (manual)

Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.


📝 Walkthrough

Walkthrough

SvelteKit now detects an enabled data-sveltekit-scroll-container element and applies scroll operations to it. Navigation, restoration, hash handling, popstate handling, and focus-reset handling use the shared scroll_to helper. Generated HTML typings and documentation describe the attribute. Browser tests cover scroll reset and back-navigation restoration.

Fixed issue severity: Medium

Merge Risk: ⚪ Minimal · up to 4a4ea

Marked app-owned scroll containers now receive navigation scrolling and history restoration, while applications without the attribute retain window scrolling. Navigation reset and back-button restoration are covered, with no remaining merge-blocking risk identified.

🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title uses the required fix: prefix and clearly describes the main change: support for app-owned scroll containers.
Backward Compatibility Impact Disclosure ✅ Passed No breaking public interface change is introduced. The PR adds an optional data-sveltekit-scroll-container attribute and a new internal scroll_to helper. Existing window scrolling remains the fall…

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Page scroll position not reset to top on navigation (regression)

1 participant