An iframe without a url

Sometimes you need to display html inside an iframe, but it’s not at a URL. Perhaps you got the markup from an API endpoint or generated it yourself. Maybe the markup is from a different domain and you need to be able to manipulate its DOM without cross-origin errors. For all these reasons, I created MarkupFrame.

A React component to display raw html markup inside an iframe

In several projects I’ve worked on recently I’ve wanted to treat the contents of an iframe as data, fetching it from an API, manipulating it directly using cheerio, and directly reaching into the iframe’s DOM to adjust the elements inside without hitting cross-domain errors.

Normally iframes are set up in such a way that these things are difficult, but there’s a trick:

iframe.contentWindow.document.open();
iframe.contentWindow.document.write( content );
iframe.contentWindow.document.close();

Those three lines allow us to inject html markup directly into the iframe, where the browser will render it: CSS, scripts, and all.

MarkupFrame takes those three lines of magic and wraps them in a React component to use in your application. You can install it using npm:

npm install markup-frame

Then just use the markup prop like this (JSX syntax):

<MarkupFrame markup={ '<h1>hello world</h1>' } />

There’s also a prop called onLoad which is a function that will be called when the markup is finished loading. The callback will be passed a reference to the document object of the iframe, which lets you directly manipulate the DOM (I know: isn’t that what React is supposed to prevent? Yes, but inside the iframe it’s a whole other world.)

...
render: function() {
  var onLoad = function( previewDocument ) {
    previewDocument.querySelector( 'h1' ).innerHTML = 'hello markup-frame';
  };
  return <MarkupFrame markup={ '<h1>hello world</h1>' } onLoad={ onLoad } />;
}
...

This has certainly been helpful to me. I hope it’s helpful to you too! The GitHub repo is here if you want to report any issues or contribute!

Caveat Lector:

Some JavaScript rendered inside an iframe like this doesn’t work correctly since it often makes assumptions about the page having a URL.

Following (clicking) on a link inside an iframe like this will load the resulting page inside the iframe, but then the iframe contents will probably no longer be accessible via its contentWindow.document object without throwing a cross-domain error. For this reason it’s recommended to disable clicking on links using the onClick prop.

Author: Payton Swick

Vegan. Digital craftsman. Tea explorer. Avid learner of things. Writes code @automattic.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s