Skip to content

feat(ui): Guarantee consuming-app global CSS can't distort Bible components - Shadow DOM - #348

Open
cameronapak wants to merge 2 commits into
mainfrom
journey-to-the-shadow-dom
Open

feat(ui): Guarantee consuming-app global CSS can't distort Bible components - Shadow DOM#348
cameronapak wants to merge 2 commits into
mainfrom
journey-to-the-shadow-dom

Conversation

@cameronapak

@cameronapak cameronapak commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator

This PR is in progress and will continue to be defined. This PR was created as a feature branch for https://lifechurch.atlassian.net/browse/YPE-4113.

Greptile Summary

This proof of concept automatically renders YouVersionAuthButton within an open Shadow DOM boundary to isolate it from consuming-application CSS.

  • Adds a reusable shadow host and higher-order isolation wrapper with constructable-stylesheet and fallback delivery paths.
  • Adds unit and Storybook coverage for hostile CSS, Strict Mode, interactions, and same-origin iframe rendering.
  • Adds a hostile-CSS demonstration page, architectural decision record, and coordinated breaking changeset.

Confidence Score: 5/5

The PR appears safe to merge because no blocking failure remains within the eligible follow-up-review scope.

No blocking failure remains.

Important Files Changed

Filename Overview
packages/ui/src/lib/shadow-root-host.tsx Introduces the shadow-root lifecycle, per-document constructed stylesheet cache, fallback style resource, host reset, and portal boundary.
packages/ui/src/lib/shadow-isolation.tsx Adds a typed ref-forwarding wrapper that places supported component implementations inside ShadowRootHost.
packages/ui/src/components/YouVersionAuthButton.tsx Moves the public authentication button behind automatic shadow isolation and explicitly applies its sans-serif font utility.
packages/ui/src/styles/global.css Adds shadow-context pseudo-element suppression for the externally selectable host.
packages/ui/src/components/YouVersionAuthButton.shadow-isolation.stories.tsx Adds browser integration scenarios for hostile global CSS and same-origin iframe stylesheet ownership.
packages/ui/src/lib/shadow-root-host.test.tsx Adds focused coverage for Strict Mode attachment, host reset declarations, and fallback resource identity.
docs/adr/0005-prototype-shadow-dom-style-isolation.md Records the prototype architecture, compatibility impact, verified scope, and deliberately deferred limitations.
examples/vite-react/src/pages/HostileCssPage.tsx Adds an interactive demonstration of host CSS attack vectors and their expected isolation behavior.
.changeset/prototype-shadow-dom-isolation.md Declares a coordinated breaking release for the fixed-version SDK package set.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  Consumer[Consumer application] --> Public[YouVersionAuthButton]
  Public --> Wrapper[withShadowIsolation]
  Wrapper --> Host[Light-DOM shadow host]
  Host --> Root[Open shadow root]
  Root --> Styles{Constructable stylesheets supported?}
  Styles -->|Yes| Adopt[Adopt document-cached SDK stylesheet]
  Styles -->|No| Fallback[Render fallback style resource]
  Adopt --> Button[Auth button implementation]
  Fallback --> Button
  Host -. blocks host selectors .-> Button
Loading

Reviews (2): Last reviewed commit: "Merge branch 'main' into journey-to-the-..." | Re-trigger Greptile

Context used (4)

* feat(ui)!: prototype automatic Shadow DOM isolation

* docs(examples): add hostile CSS POC demo

* docs(examples): clarify hostile CSS vectors

* docs(ui): align shadow DOM prototype ADR

* test(ui): strengthen shadow isolation proof

* refactor(ui): remove shadow isolation type assertions

* fix(ui): block hostile shadow host pseudo-elements

* docs(ui): clarify shadow isolation trade-offs

* test(ui): align shadow isolation demo conventions

* docs(examples): keep hostile demo labels readable

* fix(ui): use style precedence for shadow fallback stylesheet

Addresses PR review feedback: the non-adoptedStyleSheets fallback
rendered a bare <style> tag inside the shadow-root portal. Use
React 19's <style href precedence> resource form instead so React
hoists and de-duplicates the stylesheet within the shadow root
rather than risking duplicate insertion.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: abharms <aharms@works24.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
@cameronapak cameronapak self-assigned this Aug 19, 2026
@changeset-bot

changeset-bot Bot commented Aug 19, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: a794931

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

This PR includes changesets to release 4 packages
Name Type
@youversion/platform-core Major
@youversion/platform-react-hooks Major
@youversion/platform-react-ui Major
vite-react 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

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.

2 participants