Skip to content

Reg Lite: support mounting inside a shadow DOM (Web Component hosts) - #159

Open
gcutrini wants to merge 1 commit into
mainfrom
feat/shadow-dom-embedding
Open

Reg Lite: support mounting inside a shadow DOM (Web Component hosts)#159
gcutrini wants to merge 1 commit into
mainfrom
feat/shadow-dom-embedding

Conversation

@gcutrini

Copy link
Copy Markdown
Member

ref: https://app.clickup.com/t/86bbm2fzf

Reg Lite can be embedded inside a shadow DOM, for example when a host renders it as a self-contained Web Component. Stripe's Payment Element cannot mount inside a shadow root: Stripe finds its payment iframes through window.frames, which cannot see into shadow trees, so the payment step would render empty.

Reg Lite now detects when it sits inside a shadow root and keeps the Payment Element in the light DOM, projecting it back in-flow through a named slot (Stripe's recommended approach, stripe/stripe-js#143). Outside a shadow root nothing changes: the Element mounts inline as before.

Result: Reg Lite works in encapsulated hosts with payments intact, end to end.

Stripe Elements cannot mount inside a shadow root — Stripe reaches its iframes through window.frames, which cannot see into shadow trees. When StripeForm is mounted in a shadow root, render the PaymentElement into a light-DOM node and project it back in-flow through a named <slot>, per Stripe's recommended workaround (stripe/stripe-js#143).

A callback ref on the form detects whether it sits in a shadow root and picks the slot path or the inline path accordingly; outside a shadow root the Element mounts inline as before.
@coderabbitai

coderabbitai Bot commented Aug 25, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 584e6b03-657d-4f61-9406-8367164d3bf2


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@santipalenque santipalenque left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gcutrini make comments consise, we don't need the full explanation just a hint or reason

<form className={styles.form} id="payment-form" onSubmit={handleSubmit(onSubmit)}>
<PaymentElement options={paymentOptions} />
<form ref={detectSlotHost} className={styles.form} id="payment-form" onSubmit={handleSubmit(onSubmit)}>
{slotHost === undefined

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dont' do chained ternary, move to an auxiliary method please.

// host element when shadow-mounted. A callback ref resolves it when the form
// node attaches — during commit, before paint — so the PaymentElement is only
// rendered once the context is known and never attempts an in-shadow mount.
const [slotHost, setSlotHost] = useState(undefined);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gcutrini No test covers the new shadow-DOM detection/portal logic (slotHost state + detectSlotHost ref + the slotted-render branch below). stripe-form had zero tests before this PR and still has none, so a regression here (wrong portal target, slot never receiving the projected element) would fail silently in production for any shadow-DOM host, with nothing catching it in CI.

Suggested fix: add a unit test that renders StripeForm inside a real ShadowRoot (jsdom 16.6, already a devDependency, supports element.attachShadow) asserting the PaymentElement wrapper lands as a light-DOM child of the shadow host with slot="stripe-payment", plus one asserting the inline (non-shadow) path is unchanged.

@smarcet smarcet left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gcutrini please review

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.

3 participants