Skip to content

feat(site): preserve scroll position on framework switch (pagereveal)#608

Merged
decepulis merged 2 commits intomainfrom
feat/scroll-restore-pagereveal
Feb 25, 2026
Merged

feat(site): preserve scroll position on framework switch (pagereveal)#608
decepulis merged 2 commits intomainfrom
feat/scroll-restore-pagereveal

Conversation

@decepulis
Copy link
Copy Markdown
Collaborator

@decepulis decepulis commented Feb 25, 2026

Summary

Preserves scroll position when switching frameworks (React ↔ HTML) on docs pages where the slug stays the same. Uses the existing native view transition infrastructure (pagereveal/pageswap events) that sidebar scroll restoration already relies on.

  • Before navigating, saves { url, scrollY } to sessionStorage from the React call sites
  • In the pagereveal handler (fires before the new page is revealed), restores scroll position if the URL matches
  • No architectural changes — still MPA, 3 files modified, ~15 lines of new code

Bake-off companion: #609 (ClientRouter approach)

Closes #484

Approach: Why pagereveal?

The @view-transition { navigation: auto } CSS (already in DocsSidebarRestoration.astro) makes the browser hold a screenshot of the old page while the new page loads. The pagereveal event fires before the screenshot is swapped out, so restoring window.scrollY here is flicker-free — the same mechanism sidebar restoration uses today.

Changes

File What
DocsSidebarRestoration.astro Restructured pagereveal handler to not early-return when sidebar is absent; added page scroll restoration from sessionStorage
Selectors.tsx Saves scroll position to sessionStorage before window.location.replace()
JSPickerClient.tsx Same pattern; removed TODO comment

Test plan

  • pnpm dev, navigate to a docs page, scroll to middle, switch framework via sidebar dropdown → scroll preserved, no flicker
  • Switch framework via JSPicker on installation page → scroll preserved
  • Navigate to page where slug changes on framework switch → scrolls to top
  • Sidebar state (scroll + details open/closed) persists across navigation
  • Dark mode and style preference persist
  • Browser back/forward work correctly
  • Hard refresh works correctly
  • Test Safari, Chrome, Firefox

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel bot commented Feb 25, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
vjs-10-demo-react Ignored Ignored Preview Feb 25, 2026 8:27pm

Request Review

@netlify
Copy link
Copy Markdown

netlify bot commented Feb 25, 2026

Deploy Preview for vjs10-site ready!

Name Link
🔨 Latest commit 199cb90
🔍 Latest deploy log https://app.netlify.com/projects/vjs10-site/deploys/699f5b162539160008a2be20
😎 Deploy Preview https://deploy-preview-608--vjs10-site.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Feb 25, 2026

📦 Bundle Size Report

Package Size Diff %
@videojs/core 5.68 kB 0 B ░░░░░░░░ 0%
@videojs/element 1.60 kB 0 B ░░░░░░░░ 0%
@videojs/html 8.63 kB 0 B ░░░░░░░░ 0%
@videojs/icons 3.46 kB 0 B ░░░░░░░░ 0%
@videojs/react 15.92 kB 0 B ░░░░░░░░ 0%
@videojs/store 1.94 kB 0 B ░░░░░░░░ 0%
@videojs/utils 2.47 kB 0 B ░░░░░░░░ 0%

Total: 39.71 kB · 0 B · 0%


Entry Breakdown

Subpath sizes are the additional bytes on top of the root entry point, measured by bundling root + subpath together and subtracting the root-only size.

@videojs/core
Entry Base PR Diff %
. 3.10 kB 3.10 kB 0 B 0%
./dom 2.58 kB 2.58 kB 0 B 0%
total 5.68 kB 5.68 kB 0 B 0%
@videojs/element
Entry Base PR Diff %
. 817 B 817 B 0 B 0%
./context 823 B 823 B 0 B 0%
total 1.60 kB 1.60 kB 0 B 0%
@videojs/icons
Entry Base PR Diff %
./react 2.10 kB 2.10 kB 0 B 0%
./html 1.37 kB 1.37 kB 0 B 0%
total 3.46 kB 3.46 kB 0 B 0%
@videojs/react
Entry Base PR Diff %
. 7.69 kB 7.69 kB 0 B 0%
./audio 266 B 266 B 0 B 0%
./background 268 B 268 B 0 B 0%
./video 7.72 kB 7.72 kB 0 B 0%
total 15.92 kB 15.92 kB 0 B 0%
@videojs/store
Entry Base PR Diff %
. 1.29 kB 1.29 kB 0 B 0%
./html 468 B 468 B 0 B 0%
./react 199 B 199 B 0 B 0%
total 1.94 kB 1.94 kB 0 B 0%
@videojs/utils
Entry Base PR Diff %
./array 104 B 104 B 0 B 0%
./dom 684 B 684 B 0 B 0%
./events 227 B 227 B 0 B 0%
./function 197 B 197 B 0 B 0%
./object 119 B 119 B 0 B 0%
./predicate 265 B 265 B 0 B 0%
./string 110 B 110 B 0 B 0%
./style 185 B 185 B 0 B 0%
./time 478 B 478 B 0 B 0%
./number 158 B 158 B 0 B 0%
total 2.47 kB 2.47 kB 0 B 0%

ℹ️ How to interpret

Sizes are minified + brotli, measured with esbuild.
Package totals are computed as root size + marginal subpath costs.
Subpath marginal cost = (root + subpath bundled together) − root alone.

Icon Meaning
No change
🔺 Increased ≤ 10%
🔴 Increased > 10%
🔽 Decreased
🆕 New (no baseline)

Run pnpm size locally to check current sizes.

Base UI's Select transfers html.scrollTop to body.scrollTop during its
scroll lock, so window.scrollY reads as 0 while the dropdown is open.
Detect the lock via data-base-ui-scroll-locked and read body.scrollTop
instead. Also normalize trailing slashes in URL comparison.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@decepulis decepulis marked this pull request as ready for review February 25, 2026 20:28
@decepulis decepulis merged commit 420742e into main Feb 25, 2026
12 checks passed
@decepulis decepulis deleted the feat/scroll-restore-pagereveal branch February 25, 2026 20:29
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.

fix(docs): jump to top of window when toggling between frameworks

1 participant