Skip to content

feat(sync): shadow root mode (research) - #548

Draft
feledori wants to merge 2 commits into
lightfrom
fdi/research
Draft

feledori wants to merge 2 commits into
lightfrom
fdi/research

Conversation

@feledori

@feledori feledori commented Oct 2, 2026

Copy link
Copy Markdown
Member

What this does

sync can now run without touching the site's html, body or panel styles at all. flex and grid bodies, body padding, sticky footers, multi-child panels and iOS-style scroll locks all behave like the plain page instead of breaking. it's opt-in behind shadow: true so you can compare it side by side with the current approach.

  • sync attaches a shadow root to body (or the panel) and builds track > content > layout > <slot> there, the site's children get slotted in untouched
  • the layout box copies body's display, alignment and min-height, gap and grid tracks are inherited, so a flex/grid body keeps laying out its children
  • anything above the track (body padding, margins) scrolls natively and gets subtracted as an offset, re-read when html/body style or class changes (scroll locks)
  • destroy() can't remove a shadow root, it leaves a bare <slot> that renders like nothing is there, and reuses it on the next construct (StrictMode, HMR)
  • playground: /sync?shadow and /sync-nested?shadow, plus nav links

Checked (desktop chrome, positions compared against the same page without sync)

mirroring, scrollTo, scrollIntoView, focus, hash anchors, flex column body, grid body, padded body, sticky footer, position: fixed; top: -scrollY scroll lock, nested panel with 2 children, scroll-timeline via body::part(content). default mode re-checked, unchanged.

Not checked / known tradeoffs

  • real iOS touch and rubber-band, safari, firefox, find-in-page through the slot
  • body padding-top is no longer synced (it was inside body before), it moves natively like a plain page
  • body { scroll-timeline } has to become body::part(content)
  • offsetParent skips the shadow boxes, so offsetTop-chain math (the playground ghosts, older parallax libs) might be off
  • only watches style/class, so locks like react-remove-scroll (data-scroll-locked + a style tag) aren't picked up yet
  • hosts that can't take a shadow root (ul, td, custom elements with their own) would need the current path as fallback

@vercel

vercel Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated
lenis-playground Building Building Preview Oct 2, 2026 11:00am UTC

This branch was successfully deployed

1 active deployment
Preview — 0bb76c9b Deployed Oct 2, 2026 by vercel[bot]
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.

1 participant