Using the adoptNode() Method with Embedded iframes

on | 3 Comments

There’s an interesting DOM feature that I just came across that’s a method of the document object that allows you to remove elements from an <iframe> that’s embedded on a page and drop them into the current page (or vice versa).

In other words, you adopt the elements from the child frame into the parent. The code for document.adoptNode() looks like this:

document.adoptNode(node)

Where node is equal to the node you want to bring in from the other document.

So let’s say I have a document called page.html that looks like this:

<body>
  <p class="one">One</p>
  <p class="two">Two</p>
  <p class="three">Three</p>
</body>

All I have here is a body element with three uniquely-classed paragraphs. Nothing special.

I’m going to embed that page as the source of an iframe inside another document that looks like this:

<iframe src="page.html"></iframe>

<p><button>ADOPT THE ELEMENTS!</button></p>

<div class="container"></div>

The button in this parent page will be used to trigger the action. Here’s the JavaScript:

let myFrame = document.querySelector('iframe'),
    myPars = myFrame.contentDocument.querySelectorAll('p'),
    container = document.querySelector('.container');

document.querySelector('button').addEventListener('click', function() {
  myPars.forEach(function(par) {
    container.appendChild(document.adoptNode(par));
  });
}, false);

To sum up the main parts of the above code:

  • I’m using the contentDocument property of the iframe object to get access to that frame’s document
  • I’m looping through the paragraphs using forEach
  • Each paragraph is adopted individually into the parent document, each one appended inside .container

Try it by visiting the demo below.

On the demo page, just click the button and you’ll see the three paragraphs disappear from the iframe and appear on the parent page. This works differently from the more commonly-known importNode() method, which more or less does the same thing, except the imported nodes stay in the original document (cloning them rather than moving them).

Re-Adopting Elements from the Parent

Now I’ll take this even further by using a second embedded iframe (page2.html) to pull the same paragraphs out of the parent frame and into the second frame. Here’s the code that I’ll run inside page2.html:

let container = document.querySelector('.container'),
    myPars = parent.document.querySelectorAll('p[class]');

document.querySelector('button').addEventListener('click', function() {
  myPars.forEach(function(par) {
    container.appendChild(document.adoptNode(par));
  });
}, false);

Here I’m doing the following:

  • Accessing the parent frame using parent.document
  • Grabbing the newly adopted paragraphs (using the class attribute to limit which ones I grab in my querySelector call)
  • Re-adopting the paragraphs into the second iframe’s document using the same kind of loop as the previous example

In this demo you’ll have to first adopt the nodes into the parent then use the second frame’s button to re-adopt them into that frame.

The class names that I originally included on the paragraphs don’t mean anything. I simply wanted to demonstrate that the elements are moved exactly as they appear in the original page. If you inspect the second frame with your developer tools, you can see the paragraphs pulled in with the class names intact, as shown in the following screenshot:

Nodes remain intact when using adoptNode()

Since these scripts are working across frames, this sort of thing would be subject to the usual cross-origin limitations. So if the child frame page is not on the same origin, the server would have to enable cross-origin resource sharing (or CORS) for that page, otherwise you’ll get an error in your console indicating a cross-origin limitation.

Use Cases for This?

The first thing that comes to mind where this might be useful is in a game context. For example a game that embeds another page in an iframe that allows the user to interact with the iframe, possibly moving items from one frame to the other.

Another example might be some kind of grid or spreadsheet-like app that embeds various iframes and maybe some Ajax keeps track of nodes that are moved from one page to the other, essentially saving the content wherever it’s “adopted”.

Finally, if you’re wondering about browser support, this works just about everywhere, including IE9 and up, so this is an older feature that has pretty wide support.

If you have any ideas on how this might be useful, I’d love to hear your comments.

3 Responses

  1. Šime Vidas:

    What would happen if I just appended these paragraphs to the parent page directly, without passing them to `document.adoptNode` first?

    • I believe the primary difference there would be that they would not disappear from the original document. So this seems to be a quick way to not only add them to the new document, but also remove them without having to use a different method to delete them first.

  2. Iframes bad for SEO, I observed and the giant search engine rules avoid the use of frames in websites what would you say?

Leave a Reply

Comment Rules: Please use a real name or alias. Keywords are not allowed in the "name" field. If you use keywords, your comment will be deleted, or your name will be replaced with the alias from your email address. No foul language, please. Thank you for cooperating.

Instructions for code snippets: Wrap inline code in <code> tags; wrap blocks of code in <pre> and <code> tags. When you want your HTML to display on the page in a code snippet inside of <code> tags, make sure you use &lt; and &gt; instead of < and >, otherwise your code will be eaten by pink unicorns.