Creating a cross-domain React component, with zoid

Daniel Brain
Mar 20, 2017 · 6 min read
Image for post
Image for post

This article is part of a series on PayPal’s Cross-Domain Javascript Suite.

React is perfect for creating isolated components, on the web.

React components allow you to isolate small, reusable bits of functionality and UI in your app, which you can treat as discrete parts of your code-base, each with its own interface. For example, if I wanted to build a log-in experience, I might build a component like:

<MyLoginComponent prefilledEmail={prefilledEmail} onLogin={onLogin} />

Once my component is built, I don’t have to care how exactly it works or how it’s implemented. I just have to drop in a prefilledEmail and an onLogin callback, and then let the component do it’s thing. It’ll then tell me via the callback when the user has finished logging in.

This is a very functional-ish pattern: the logic and behavior of my component can be totally isolated from the rest of my app, like in a pure-function. It can self-contain its own styles, its own behavior, its own event handlers, and even its own tests.

OK, but you’re preaching to the choir here, we already love React

OK then, let’s talk about some of the things React can’t do.

React components aren’t easily shared or distributed. If I build a component, it’s very easy to drop it into my own site, but if I want to let you use the same component on your site, there are a lot of questions to answer first:

So just drop the experience in an iframe?

That definitely solves the security problem, but iframes aren’t exactly flexible.

So what do we do?

This is where zoid comes in!

With zoid, I can build a React component and make it work entirely cross-domain, in an iframe, without once thinking about setting up DOM elements, postMessage listeners or forcing all of my props into a url’s query string.

If you want to get a really good understanding of what zoid does, I’ve written about it a lot, elsewhere. But for now let’s just give it a go, and turn a same-domain React component into a cross-domain React component!

First let’s build a simple component.

What better than the MyLoginComponent we imagined earlier!

First, let’s write some boilerplate for a simple React component, and render it into our page:

let MyLoginComponent = React.createClass({    getInitialState() {
return { email: this.props.prefilledEmail };
render() { }
<MyLoginComponent />,

Our component is going to handle one event: a button click on a login button. So let’s set up a handler for that. We’ll introduce an artificial delay, then call that onLogin callback.

let login = () => {
setTimeout(() => {
}, 2000);

Next, we need to return some JSX to render our component, with an email field, a password field, and a button. We also want to pre-populate the email field, if we were passed a prefilledEmail:

return (
defaultValue={ }
onChange={ event =>
this.setState({ email: })
<br/> <input
placeholder='password' type='password'
onChange={ event =>
this.setState({ password: })
<br/> <button
className='btn btn-primary'
onClick={ login }> Log In

And we’re done! We have something resembling a log-in component. It has no validation or server calls, but you can worry about implementing that later. The important thing is:

Image for post
Image for post

You can see the full example code for this here. It has a few extra nice features, like a loading spinner, but fundamentally it’s just a pure React component.

So how do we make it work cross-domain?

OK, so we want other people to be able to render our component from their site. We’re going to have to do a few things to enable this. Most of these should be pretty straightforward.

1. Set up a zoid component

This is where zoid comes in. We need to set up a definition for our component, with the url, and a tag name for our component.

let MyLoginZoidComponent = zoid.create({    tag: 'my-login-component',
url: ''

You can see the full demo code for this here.

This zoid definition, along with the zoid library, need to be loaded in a script tag in both the component page and the parent window where we want to render the component. It’ll provide a way for the iframe to communicate with the parent, and vice-versa.

2. Pass in the props

When we rendered the component earlier, we did:

<MyLoginComponent />,

We need to change this slightly. Now, additionally, we need to pass in the props we’ve been passed from the parent window, like so:

<MyLoginComponent { ...window.xprops } />,

3. Host it

Now host the React component somewhere on a web-server. We need the html page you just created to be behind some url, so that we can load it in an iframe. In the component definition earlier, we specified url: '' — this url needs to match whatever url you host your component under.

4. Render it!

Now you’re ready to use the component on some different domain, or if you’re sharing it with other people, let them know they can use it on their site!

let App = React.createClass({    render() {    let onLogin = (email) =>
alert(`User logged in with email: ${email}!`);
return (
<h3>Log in</h3>
onLogin={ onLogin } />
ReactDOM.render(<App />, document.querySelector('#container'));
Image for post
Image for post

Note here we’re using MyLoginComponent.react, which is the React component zoid generates for us (remember, the original React component is going to be living in our iframe, where the parent page can’t directly access or render it).

You can see/run the full code example for rendering the component here.

What if the person I’m sharing with doesn’t have/want React?

No problem! zoid comes with a vanilla javascript way to render the component:

MyLoginZoidComponent.render({    prefilledEmail: '',

onLogin: function() {
alert('User logged in with email: ' + email);
}, '#container');

Now anyone can use your React component on their site, without ever realizing they’re using a React component inside the iframe! To them, that’s just an implementation detail — in fact, the fact that they’re using an iframe at all is just an implementation detail.

And we’re done!

Congrats, you’ve just made your component work for anyone who wants to load it into their site!

To make this easier, you can bundle together your component definition with zoid.js and host it somewhere, so whoever wants to use your component can simply do:

<script src=""></script><script>
MyLoginZoidComponent.render({ ... }, '#container');


Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch

Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore

Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store