fix: support position-anchor on a custom-element host#415
Open
jpzwarte wants to merge 5 commits into
Open
Conversation
Make `position-anchor` work when set on a custom-element host whose `anchor()` functions live in the shadow root's `:host` rule. This introduces CSS tree-scoping into the polyfill: - Tag every `StyleData`/`Selector` with the tree (document or shadow root) it was authored in, threaded through fetch, transform and `getSelectors`. - Resolve `:host` / `:host(...)` target rules to the shadow host, which `querySelectorAll` cannot return (`hostMatchesSelector`). - Extend the anchor search to the target's own tree when a shadow host sets `position-anchor` in its own inline style, so the anchor in the outer (light DOM) tree is found — without leaking shadow-scoped names across the boundary. Adds the `<position-anchor-on-host>` demo and an e2e test covering it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
✅ Deploy Preview for anchor-polyfill ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
✅ Deploy Preview for anchor-position-wpt canceled.
|
✅ Deploy Preview for anchor-position-wpt canceled.
|
jpzwarte
commented
Jun 18, 2026
| const match = /^:host\(\s*(.+?)\s*\)$/.exec(trimmed); | ||
| if (match) { | ||
| try { | ||
| return host.matches(match[1]); |
Contributor
Author
There was a problem hiding this comment.
I reverted this line to the original one; What's in between :host(...) can be passed to matches() just fine afaik. I don't see a need to parse the CSS here (i tested the .blue, .red manually against matches())
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Make
position-anchorwork when set on a custom-element host whoseanchor()functions live in the shadow root's:hostrule — including multiple such hosts on a page, and hosts that share a single constructed stylesheet.Positioning a shadow host
:host/:host(...)target rules to the shadow host element, whichquerySelectorAllcannot return (hostMatchesSelector).position-anchorin its own inline style, so the anchor in the outer (light DOM) tree is found — without leaking shadow-scoped names across the boundary.Concurrent, per-host polyfill runs
Each shadow root that adopts an anchor stylesheet schedules its own
polyfill()run (shadow.ts). Those runs are async and were interleaving over shared state, so with two<position-anchor-on-host>hosts only the last one positioned correctly. The runs are now safe to overlap — with each other and with a user-initiatedpolyfill()— without any queue or coordinator:parseCSSsnapshots theanchorNames/anchorScopesregistries before its firstawaitand passes them togetAnchorEl, so a concurrent run'sresetStores()can no longer wipe the registries a run is resolving against mid-flight.data-has-inline-stylesids — reused instead of re-minted each run (and no longer stripped on cleanup), so a concurrent run's anchor selector can't go stale.--anchor-*mappings another run added are preserved (re-read at write time).Shared constructed stylesheets
A constructed stylesheet adopted by multiple shadow roots ("construct once, adopt everywhere") is no longer mutated in place — each adopting root receives a polyfill-owned copy with its own rewritten custom properties, so all hosts resolve, not just the last.
Demo & tests
The
<position-anchor-on-host>demo now uses one shared stylesheet across two linked hosts, and the e2e test asserts that every host is positioned above its own anchor — not just the last. Verified across many real-browser (Firefox) runs.Closes #408