Skip to content

feat: use shadow dom#169

Open
njesenberger wants to merge 4 commits intobenjitaylor:mainfrom
njesenberger:feat/shadow-dom
Open

feat: use shadow dom#169
njesenberger wants to merge 4 commits intobenjitaylor:mainfrom
njesenberger:feat/shadow-dom

Conversation

@njesenberger
Copy link
Copy Markdown
Contributor

Migrate toolbar to Shadow DOM for style isolation

This PR moves the toolbar into a Shadow DOM host, preventing CSS from leaking between the toolbar and the host page in either direction.

What changed

Shadow DOM encapsulation
The toolbar's React tree is now rendered inside a shadow root via a new ShadowRoot component. All stylesheets are collected as raw CSS strings and injected as a single <style> tag inside the shadow root, replacing the previous approach of scattering individual <style> tags across document.head. A new reset.scss provides baseline normalization scoped to :host so host-page resets can't bleed in.

Build pipeline refactor
The scssModulesPlugin in tsup.config.ts has been simplified. Each SCSS file previously generated runtime code that appended style elements to document.head — now CSS modules export a named css string alongside the default class-name map, and plain .scss files export only a css string. The component concatenates these into one <style> tag rendered inside the shadow root. scss.d.ts is updated to match, and esbuild is now an explicit dev dependency rather than a transitive one.

Color token CSS
The injectAgentationColorTokens function that imperatively wrote to document.head at module load time has been replaced with a static CSS string using :host selectors, injected alongside the other styles inside the shadow root.

CSS fixes for Shadow DOM compatibility
Two :has() selectors that don't work reliably across shadow boundaries have been replaced with explicit data-checked attribute checks in Checkbox and Switch. Both components now set data-checked on their wrapper div and use .container[data-checked] in their stylesheets instead.

Bug fixes

  • The drag preview element is appended to portalWrapperRef.current (inside the shadow DOM) rather than document.body, so it picks up shadow-scoped styles correctly
  • RearrangeOverlay now queries its own shadow root for [data-rearrange-section] elements instead of document, preventing potential mismatches
  • Cursor override styles no longer need a :not([data-agentation-root] *) exclusion since the toolbar is naturally isolated inside its shadow root
  • webkit-user-select: none added throughout for Safari compatibility

Cleanup
Removed dead CSS from styles.module.scss: unused .canvasPurpose* blocks and .customCheckbox, .toggleLabel, .toggleSwitch, .toggleSlider, which are superseded by the Checkbox and Switch components.

@vercel
Copy link
Copy Markdown

vercel bot commented Mar 30, 2026

@njesenberger is attempting to deploy a commit to the Benji Taylor's Projects Team on Vercel.

A member of the Team first needs to authorize it.

@njesenberger njesenberger marked this pull request as draft March 30, 2026 13:18
@njesenberger njesenberger marked this pull request as ready for review March 30, 2026 13:20
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