Move elements around the DOM while preserving their state with moveBefore

~

moveBefore?

New in Chrome 133 (which goes stable on Feb 4) is a new method to move an element around the DOM: Node.prototype.moveBefore. While small in size, this method is a very big deal because it preserves the element’s state when moving them around! For example:

  • Iframes remain loaded
  • Active element remains focus
  • Popovers, fullscreen, modal dialogs remain open
  • CSS transitions and animations carry on

~

Old vs new

The classic way of moving things around is to use Node.prototype.insertBefore. When doing so the node that was “moved” reloads with its initial state.

document.querySelector('#classic').addEventListener('click', () => {
	const $newSibling = getRandomElementInBody();
	const $iframe = document.querySelector('iframe');

	document.body.removeChild($iframe);
	document.body.insertBefore($iframe, $newSibling);
});

Even if you leave out the call to removeChild, the insertBefore will still do that all by itself – even if the target is still connected to a parent. I’ve left it in to make what is going on behind the scenes more explicit.

The new way of moving elements around is to use moveBefore. Syntax-wise the method is modeled after insertBefore so that you can swap things out easily.

document.querySelector('#classic').addEventListener('click', () => {
	const $newSibling = getRandomElementInBody();
	const $iframe = document.querySelector('iframe');
	
	document.body.moveBefore($iframe, $newSibling);
});

With moveBefore the state of the moved element is preserved.

~

Demo

Here’s a demo that includes both approaches.

See the Pen DOM State-Preserving Move (Node.prototype.moveBefore) by Bramus (@bramus) on CodePen.

If your browser does not support moveBefore, check out this video to see it in action. The YouTube embed – which is an iframe – keeps playing as the iframe gets moved around.

~

The effect on MutationObserver and Web Components

If you have a MutationObserver, using moveBefore will – just like insertBefore – generate two mutations: one for the removal and one for adding the element onto its new parent. This choise was made for compatibility reasons.

When using Web Components the connectedMoveCallback method will fire if you have specified it. If you do not have specified a connectedMoveCallback method, the regular disconnectedCallback and connectedCallback will fire (again for backwards compat reasons) with isConnected being true.

~

Browser Support

Browser support is limited to Chrome 133+ at the time of writing. Both Safari and Firefox have expressed (1, 2) their support for this new API.

You can feature detect availability of moveBefore as follows:

if (!("moveBefore" in Element.prototype)) {
 // Not supported
}

~

Spread the word

Feel free to reshare one of the following posts on social media to help spread the word:

~

Published by Bramus!

Bramus is a frontend web developer from Belgium, working as a Chrome Developer Relations Engineer at Google. From the moment he discovered view-source at the age of 14 (way back in 1997), he fell in love with the web and has been tinkering with it ever since (more …)

Unless noted otherwise, the contents of this post are licensed under the Creative Commons Attribution 4.0 License and code samples are licensed under the MIT License

Join the Conversation

1 Comment

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.