We can finally move elements in the browser with the moveBefore() API
Written by Chizaram Ken✏️ The newly announced moveBefore() API helps developers easily reposition DOM elements while preserving their state. This new API is particularly valuable for web applications with complex animations and more nuanced state management. Chrome recently announced the moveBefore() API. If this is your first time coming across this API, it just might be a game-changer. When it comes to moving elements around your webpage, the DOM has traditionally been limited to removing and inserting primitives. For the past twenty years, whenever we as developers "move" elements within a webpage, what really happens behind the scenes is that we remove and then insert that element elsewhere. The element also tends to lose its initial state. There is a workaround for this, but it's a bit complicated for such a menial task. This is exactly why we have the moveBefore() API. In this article, we’ll discuss how DOM elements were moved previously, and what difference the moveBefore() API brings. We will also look at the benefits of using moveBefore() over more traditional methods, such as appendChild()or insertBefore(). Feel free to clone this demo project to see moveBefore() in action. Introduction to MoveBefore() The moveBefore() API is available on any DOM node, and its syntax looks like this: parentNode.moveBefore(nodeToMove, referenceNode); Let’s break down the syntax above: parentNode This is the destination where you want your element to end up. It must be a node capable of having children. Example: If you have , document.getElementById('container2') could be your parentNode. nodeToMove This is the element you’re relocating. It can already be in the DOM (attached to another parent) or detached (not currently in the DOM). Unlike older methods, moving it with moveBefore() preserves its state. Example: An you want to shift from one container to another. referenceNode This specifies where nodeToMove lands among parentNode's children. It must be a direct child of parentNode or null. If it’s a child (e.g, inside ), nodeToMove is inserted right before it. If it’s null, nodeToMove goes to the end of parentNode's child list (like appendChild). Example: If parentNode has and , passing the as referenceNode places nodeToMove between and . Characteristics of moveBefore() Atomic move – Unlike appendChild or insertBefore, which remove and re-insert the node, moveBefore() performs an "atomic" move. This means the node’s internal state stays intact Same arguments as insertBefore() – The syntax mirrors insertBefore (node, referenceNode) for familiarity, but the behavior is different Error handling – If referenceNode isn’t a child of parentNode (and isn’t null), or if nodeToMove can’t be moved (e.g, it’s an ancestor of parentNode), it throws a DOMException What is the purpose of the moveBefore() API? To understand the why behind moveBefore(), we need to understand how DOM manipulation actually works. At its very core, DOM manipulation involves methods like appendChild(), insertBefore(), and removeChild(). When you want to move an element – let’s say, shifting a from one parent to another – you typically remove it from its current location and reattach it elsewhere. For example: const element = document.querySelector("#myElement"); const newParent = document.querySelector("#newParent"); newParent.appendChild(element); The code above will detach myElement from its original parent and append it to newParent. Simple, right? But while this approach works for basic repositioning, it fails to maintain its ease for complex applications. I can point out three major problems you may face with the previous pattern of moving, i.e, detaching and attaching in the real sense. State loss Let’s consider an example of an element being detached and reattached. In this case, a CSS animation or iframe content's internal state will reset. For instance, a running CSS animation might restart from its initial keyframe, disrupting the user experience. Performance issues Moving elements by detaching and reattaching them will trigger reflows and repaints in the browser’s rendering engine. In a small DOM tree, this might be negligible. But in a large application, this operation can lead to jank, slowing down the interface. Verbose code In order to preserve state or performance, we must write workarounds, storing input values in variables, pausing animations, or debouncing reflows. What should have been straightforward becomes bloated. A real-world example of implementing the moveBefore()API Let’s imagine you are designing a webpage for a course where users watch a video lecture while taking notes or viewing supplementary content. The video will be embedded in an , either from YouTube or Vimeo. The interface has two major layouts: Full-screen video mode – The video takes up most

Written by Chizaram Ken✏️
The newly announced moveBefore()
API helps developers easily reposition DOM elements while preserving their state. This new API is particularly valuable for web applications with complex animations and more nuanced state management. Chrome recently announced the moveBefore()
API.
If this is your first time coming across this API, it just might be a game-changer. When it comes to moving elements around your webpage, the DOM has traditionally been limited to removing and inserting primitives.
For the past twenty years, whenever we as developers "move" elements within a webpage, what really happens behind the scenes is that we remove and then insert that element elsewhere. The element also tends to lose its initial state. There is a workaround for this, but it's a bit complicated for such a menial task. This is exactly why we have the moveBefore()
API.
In this article, we’ll discuss how DOM elements were moved previously, and what difference the moveBefore()
API brings. We will also look at the benefits of using moveBefore()
over more traditional methods, such as appendChild()or insertBefore()
. Feel free to clone this demo project to see moveBefore()
in action.
Introduction to MoveBefore()
The moveBefore()
API is available on any DOM node, and its syntax looks like this:
parentNode.moveBefore(nodeToMove, referenceNode);
Let’s break down the syntax above:
parentNode
This is the destination where you want your element to end up. It must be a node capable of having children. Example: If you have ,
document.getElementById('container2')
could be your parentNode
.
nodeToMove
This is the element you’re relocating. It can already be in the DOM (attached to another parent) or detached (not currently in the DOM). Unlike older methods, moving it with moveBefore()
preserves its state. Example: An you want to shift from one container to another.
referenceNode
This specifies where To understand the why behind The code above will detach Let’s consider an example of an element being detached and reattached. In this case, a CSS animation or Moving elements by detaching and reattaching them will trigger reflows and repaints in the browser’s rendering engine. In a small DOM tree, this might be negligible. But in a large application, this operation can lead to jank, slowing down the interface.
In order to preserve state or performance, we must write workarounds, storing input values in variables, pausing animations, or debouncing reflows. What should have been straightforward becomes bloated.
Let’s imagine you are designing a webpage for a course where users watch a video lecture while taking notes or viewing supplementary content. The video will be embedded in an You want to make users toggle between these layouts, and you want the video to keep playing without interruption as it moves between positions. It would be unfair if the video restarts every time the user switches layouts. Just imagine losing your spot in a 20-minute lecture just because you opened the notes – that would be so annoying! Using the old traditional As of April 2025, In this article, we examined in detail how to use the Thank you for hanging by; feel free to talk about other ways we could utilize this new API in the comments. Keep coding, my friends!
NPM: Script Tag: 3.(Optional) Install plugins for deeper integrations with your stack:
nodeToMove
lands among parentNode's
children. It must be a direct child of parentNode
or null. If it’s a child (e.g, inside
nodeToMove
is inserted right before it. If it’s null, nodeToMove
goes to the end of parentNode's
child list (like appendChild
). Example: If parentNode
has and
, passing the
as
referenceNode
places nodeToMove
between and
.
Characteristics of
moveBefore()
appendChild
or insertBefore
, which remove and re-insert the node, moveBefore()
performs an "atomic" move. This means the node’s internal state stays intactinsertBefore()
– The syntax mirrors insertBefore
(node
, referenceNode
) for familiarity, but the behavior is differentparentNode
(and isn’t null), or if nodeToMove
can’t be moved (e.g, it’s an ancestor of parentNode
), it throws a DOMException
What is the purpose of the
moveBefore()
API?
moveBefore()
, we need to understand how DOM manipulation actually works. At its very core, DOM manipulation involves methods like appendChild()
, insertBefore()
, and removeChild()
. When you want to move an element – let’s say, shifting a
const element = document.querySelector("#myElement");
const newParent = document.querySelector("#newParent");
newParent.appendChild(element);
myElement
from its original parent and append it to newParent
. Simple, right? But while this approach works for basic repositioning, it fails to maintain its ease for complex applications. I can point out three major problems you may face with the previous pattern of moving, i.e, detaching and attaching in the real sense.
State loss
iframe
content's internal state will reset. For instance, a running CSS animation might restart from its initial keyframe, disrupting the user experience.
Performance issues
Verbose code
A real-world example of implementing the
moveBefore()
API
, either from YouTube or Vimeo. The interface has two major layouts:
appendChild()
DOM method, we’d implement it like so:
charset="UTF-8">
We can see above that the
iframe
in question moves, but it loses its state. In this case, you will need an extra code workaround to enable this work. But with the introduction of moveBefore()
, we no longer need workarounds for something so basic:
lang="en">
charset="UTF-8">
In the GIF above, we can see how seamless it is.
Browser support
moveBefore()
is supported in Chrome 133+. Safari and Firefox have expressed interest, but we are still unable to use the moveBefore()
API in those browsers. This is a drawback for the API, so I advise employing a fallback:
if ("moveBefore" in Element.prototype) {
// Supported
} else {
// Fallback to appendChild or insertBefore
}
Conclusion
moveBefore()
API. We’ve seen its beauty and the positive effects it brings to a unique aspect of software development. Though it is yet to be introduced to other browsers, I’d predict we’ll be using this in Safari a few months from now.
Get set up with LogRocket's modern error tracking in minutes:
LogRocket.init()
must be called client-side, not server-side.
$ npm i --save logrocket
// Code:
import LogRocket from 'logrocket';
LogRocket.init('app/id');
Add to your HTML:
<script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script>
<script>window.LogRocket && window.LogRocket.init('app/id');</script>