This library doesn't seem to work when rendering inside an iframe.
A few things I noticed:
We could not retrieve data from the specified Element. Please make sure the Element you are attempting to use is still mounted.To duplicate, simply wrap it with Frame from react-frame-component like so:
<StripeProvider apiKey="pk_test_6pRNASCoBOKtIshFeQd4XMUh">
<Frame>
<Checkout />
</Frame>
</StripeProvider>
Remove the Frame and it works again. I've tested this using the code directly from https://jsfiddle.net/g9rm5qkt/.
My guess is that it has something to do with the global window or document.
FWIW I tried to make my own Frame component, just in case the issue was with react-frame-component. Got the same error using this:
class Frame extends Component {
render() {
const { children, ...passProps } = this.props
return (
<div>
<iframe
{...passProps}
ref={iframe => {
if (this.target) return
this.target = document.createElement("div")
iframe.contentDocument.body.appendChild(this.target)
this.forceUpdate()
}}
/>
{this.target && ReactDOM.createPortal(children, this.target)}
</div>
)
}
}
<Frame>
<Checkout />
</Frame>
Hi @robertgonzales! Unfortunatly, I don't think Stripe.js is built to support the use case you describe. Stripe.js uses iframes internally to sandbox the collection of sensitive payment information. Sticking an iframe between these two components interferes with their ability to communicate and access the DOM, like you mention.
I'm curious, what's your use case? What does adding an iframe here help you do?
This library doesn't seem to work when rendering inside an iframe.
@robertgonzales To be clear, Stripe.js works within iframes, e.g. here. It's only when straddling iframes that this breaks. Specifically, you'll want to put StripeProvider within the iframe as well, and make sure the frame itself has loaded Stripe.js v3.
@jenan-stripe I've updated the title to be more clear.
Rendering StripeProvider inside or outside the iframe makes no difference. The issue seems to be with the elements mounting, not StripeProvider initialization.
@jez my use case is an embeddable app. Part of the app exists outside the iframe, and part of the app has to exist inside the iframe (mostly for style encapsulation). You're right that I could work around this by using a src w/ the iframe rather than rendering. I'd like to avoid that if possible so I'm not loading the app twice.
Thanks for the quick responses.
Hello @robertgonzales
I have the same problem, and I burned a lot of time trying to figure why it doesn't work :(
In my case I have chat-like React app, an I want to embed payment into it. Similar to Stripe Payment button, but I cannot use it, because of some constraints.
Have you got any idea on how one can work around it ?
Can you please elaborate on:
I could work around this by using a src w/ the iframe rather than rendering
I would love to hear from you on this matter.
i.e. you create two apps鈥攐ne for embedding, and one for handling payment w/ Stripe. The embedded app renders an iframe with src that points to the _separately hosted_ payment app.
I actually ended up with another solution (just as hacky, but more manageable):
My embedded app uses ReactDOM.createPortal to render Stripe Elements in context but _outside_ the rest of the app. Since Stripe Elements is iframed anyways, the final render is basically an iframe (Stripe Elements) absolutely positioned on top of another iframe (my embed app).
~Basically Stripe Elements doesn't work outside window.top context and there's no great solution.~
Basically Stripe Elements doesn't work in a different window context than code execution.
So the question becomes, is there a way to host code at the window.top level but execute it in another (iframe) window context? I'm not sure this is possible but there's some interesting discussion here.
As I see it, the only other option is to update Stripe.js v3 with a custom window option so it can bind itself to another execution context. (I totally understand why this is unlikely to happen).
So there's no great solution but for now I'm okay with the other hacky workarounds.
Basically Stripe Elements doesn't work outside window.top context and there's no great solution.
@robertgonzales Small clarification: Elements does work within iframes (e.g. see my link above) where window !== window.top. It's specifically when parts of the Stripe.js v3 straddle iframes (e.g. load https://js.stripe.com/v3/ in the outer window and try and use Elements within an iframe) that things break down.
I'm not familiar with the details of how react-frame-component and others render _into_ iframes, but I suspect if you can get the iframes to load https://js.stripe.com/v3, instantiate a stripe instance within the inner context, and use that for your Elements instances, it should work.
@robertgonzales have you made any progress on this? It looks to us like this should work as long as stripe.js is loaded in the same frame that renders the Element.
I'm going to close this, as it's been open a while and I don't think it's an issue with react-stripe-elements itself, but I'm happy to reopen if the suggestion above isn't working.
Most helpful comment
@robertgonzales Small clarification: Elements does work within iframes (e.g. see my link above) where
window !== window.top. It's specifically when parts of the Stripe.js v3 straddle iframes (e.g. loadhttps://js.stripe.com/v3/in the outer window and try and use Elements within an iframe) that things break down.I'm not familiar with the details of how
react-frame-componentand others render _into_ iframes, but I suspect if you can get the iframes to loadhttps://js.stripe.com/v3, instantiate astripeinstance within the inner context, and use that for your Elements instances, it should work.