Element: moveBefore() method
Limited availability
This feature is not Baseline because it does not work in some of the most widely-used browsers.
Experimental: This is an experimental technology
Check the Browser compatibility table carefully before using this in production.
The moveBefore()
method of the Element
interface moves a given Node
inside the invoking node as a direct child, before a given reference node.
Syntax
moveBefore(movedNode, referenceNode)
Parameters
movedNode
-
A
Node
representing the node to be moved. Note that this must be anElement
or aCharacterData
node. referenceNode
-
A
Node
thatmovedNode
will be moved before, ornull
. If the value isnull
,movedNode
is inserted at the end of the invoking node's child nodes.
Return value
None (undefined
).
Exceptions
HierarchyRequestError
TypeError
-
Thrown in any of the following situations:
- The specified
movedNode
is not part of the DOM, and you are trying to move it inside a node that is part of the DOM, or vice versa. - The specified
movedNode
is an ancestor of the ElementmoveBefore()
is being called on. - You are trying to move
movedNode
between two different documents. - The specified
movedNode
is not anElement
orCharacterData
node.
- The specified
NotFoundError
TypeError
-
The specified
referenceNode
is not a child of the node you are callingmoveBefore()
on, that is, the node you are trying to movemovedNode
inside. TypeError
TypeError
-
The second argument was not supplied.
Description
The moveBefore()
method moves a given node to a new place in the DOM. It provides similar functionality to the Node.insertBefore()
method, except that it doesn't remove and then reinsert the node. This means that the state of the node (which would be reset if moving it with insertBefore()
and similar mechanisms) is preserved after the move. This includes:
- Animation and transition state.
loading state.
- Interactivity states (for example,
:focus
and:active
). - Fullscreen element state.
- Open/close state of popovers.
- Modal state of
elements (modal dialogs will not be closed).
The play state of and
elements is not included in the above list, as these elements retain their state when removed and reinserted, regardless of the mechanism used.
When observing changes to the DOM using a MutationObserver
, nodes moved with moveBefore()
will be recorded with a removed node and an added node.
moveBefore()
constraints
There are some constraints to be aware of when using moveBefore()
:
- It can only work when moving a node within the same document.
- It won't work if you try to move a node that is not connected to the DOM to an already connected parent, or vice versa.
In such cases, moveBefore()
will fail with a HierarchyRequestError
exception. If the above constraints are requirements for your particular use case, you should use Node.insertBefore()
instead, or use try...catch
to handle the errors that arise from such cases.
Moving custom elements while preserving state
Each time a custom element's position in the DOM is updated via Element.moveBefore()
, or similar methods such as Node.insertBefore()
, its disconnectedCallback()
and connectedCallback()
lifecycle callbacks are fired. Since these callbacks are typically used to implement any required initialization or cleanup code to run at the start or end of the element's lifecycle, running them when the element is moved (rather than removed or inserted) may cause problems with its state.
You can use the connectedMoveCallback()
callback to preserve a custom element's state. When using moveBefore()
to move a custom element, connectedMoveCallback()
is run instead of connectedCallback()
and disconnectedCallback()
.
See Moving custom elements for further information.
Examples
Basic moveBefore()
usage
In this demo we illustrate basic usage of moveBefore()
.
HTML
The HTML features an We provide some rudimentary styling for the look and feel and spacing of the boxes, and use flexbox to center their content. In our script, we attach a click event listener to the The rendered example looks like this: Try clicking the In this demo we provide multiple mechanisms to move a The HTML features an We use flexbox for the layout to make the two In our script, we attach The rendered example looks like this: Try playing the YouTube embed and then clicking each element containing a
elements. The
, which we later use to move it.
Section 1
Section 2
CSS
#section1,
#section2,
#mover {
width: 200px;
height: 80px;
border: 5px solid rgb(0 0 0 / 0.25);
margin-bottom: 10px;
display: flex;
align-items: center;
justify-content: center;
}
#section1,
#section2 {
background-color: hotpink;
}
#mover {
background-color: orange;
}
JavaScript
via
addEventListener()
. When the button is clicked, we check whether the nextElementSibling
of our mover
element. If so, we invoke
moveBefore()
on the wrapper
and specify to move the
. If not, we use
moveBefore()
to move the .
const wrapper = document.getElementById("wrapper");
const section1 = document.getElementById("section1");
const section2 = document.getElementById("section2");
const mover = document.getElementById("mover");
const moveBtn = document.querySelector("button");
moveBtn.addEventListener("click", () => {
if (mover.nextElementSibling === section1) {
wrapper.moveBefore(mover, section2);
} else {
wrapper.moveBefore(mover, section1);
}
});
Result
a few times and note how it toggles between the two positions.
Demonstrating state preservation
moveBefore()
preserves the play state of the embed, but the other mechanisms do not.
HTML
element containing two
elements. The first
element contains a
elements, to which we will add functionality to move the embed
CSS
elements sit side-by-side, and space the buttons evenly inside the
controls
#wrapper,
#controls {
width: 100%;
display: flex;
}
#wrapper {
margin-bottom: 10px;
}
section {
flex: 1;
padding: 10px;
}
#controls {
display: flex;
justify-content: space-around;
}
#section1 {
background-color: hotpink;
}
#section2 {
background-color: orange;
}
#mover {
max-width: 100%;
background-color: black;
}
JavaScript
click
event listeners to each via
addEventListener()
. When the buttons are clicked, we check which element is the
parentElement
of our embed moveBefore()
, insertBefore()
, or prepend()
) to move it inside the other element.
const section1 = document.getElementById("section1");
const section2 = document.getElementById("section2");
const mover = document.getElementById("mover");
const moveBeforeBtn = document.getElementById("move-before");
const insertbeforeBtn = document.getElementById("insertbefore");
const prependBtn = document.getElementById("prepend");
moveBeforeBtn.addEventListener("click", () => {
if (mover.parentElement === section1) {
section2.moveBefore(mover, null);
} else {
section1.moveBefore(mover, null);
}
});
insertbeforeBtn.addEventListener("click", () => {
if (mover.parentElement === section1) {
section2.insertBefore(mover, null);
} else {
section1.insertBefore(mover, null);
}
});
prependBtn.addEventListener("click", () => {
if (mover.parentElement === section1) {
section2.prepend(mover);
} else {
section1.prepend(mover);
}
});
Result
a couple of times to toggle the
insertBefore()
and prepend()
, the embed state is reset after each move so it needs to be restarted. However, in the case of moveBefore()
, the state is preserved after each move.Specifications
Specification DOM
# dom-parentnode-movebeforeBrowser compatibility
See also