Creating a cross-domain React component, with zoid

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

  • Do I have any javascript, css, or anything other code that’s going to conflict with the code already on your page?
  • What if you’re using a different UI framework to me, like Angular or Ember, or you’re not using a framework at all?
  • What if my component does something that it would be insecure to expose to your site? Like, for example, accepting credentials for my domain in an html form, which I don’t want you to be able to snoop on.

So just drop the experience in an iframe?

  • I have to send everything across in the url, or wait until the frame is loaded and send down a postMessage.
  • I have to manually set up postMessage listeners t0 get data back up.
  • Even then, the data I can send back and forth is limited to things I can serialize down to JSON. So callbacks are out of the picture.

So what do we do?

First let’s build a simple component.

let MyLoginComponent = React.createClass({    getInitialState() {
return { email: this.props.prefilledEmail };
},
render() { }
});
ReactDOM.render(
<MyLoginComponent />,
document.querySelector('#container')
);
let login = () => {
setTimeout(() => {
this.props.onLogin(this.state.email);
}, 2000);
};
return (
<form>
<input
placeholder='email'
defaultValue={ this.state.email }
onChange={ event =>
this.setState({ email: event.target.value })
}
></input>
<br/> <input
placeholder='password' type='password'
onChange={ event =>
this.setState({ password: event.target.value })
}
></input>
<br/> <button
className='btn btn-primary'
onClick={ login }> Log In
</button>
</form>
);
  • It populates the email from this.props.prefilledEmail
  • It calls this.props.onLogin() when the button is clicked

So how do we make it work cross-domain?

1. Set up a zoid component

let MyLoginZoidComponent = zoid.create({    tag: 'my-login-component',
url: 'https://www.my-site.com/login'
});

2. Pass in the props

ReactDOM.render(
<MyLoginComponent />,
document.querySelector('#container')
);
ReactDOM.render(
<MyLoginComponent { ...window.xprops } />,
document.querySelector('#container')
);

3. Host it

4. Render it!

let App = React.createClass({    render() {    let onLogin = (email) =>
alert(`User logged in with email: ${email}!`);
return (
<div>
<h3>Log in</h3>
<MyLoginZoidComponent.react
prefilledEmail='foo@bar.com'
onLogin={ onLogin } />
</div>
);
}
});
ReactDOM.render(<App />, document.querySelector('#container'));

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

MyLoginZoidComponent.render({    prefilledEmail: 'foo@bar.com',

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

And we’re done!

<script src="https://www.your-site.com/loginComponent.js"></script><script>
MyLoginZoidComponent.render({ ... }, '#container');
</script>

--

--

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