Reg Lite: support mounting inside a shadow DOM (Web Component hosts) - #159
Reg Lite: support mounting inside a shadow DOM (Web Component hosts)#159gcutrini wants to merge 1 commit into
Conversation
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.
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 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. Comment |
santipalenque
left a comment
There was a problem hiding this comment.
@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 |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
@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.
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.