Replacing all children of an HTMLElement?
Asked Answered
E

6

71

In my code, I fairly frequently need to replace all children of a certain HTML container with a new list of children.

What is the fastest way to do this? My current approach is collecting all new elements into a DocumentFragment. The only way I've found to then actually replace the children is to remove all the children one by one, and append the fragment. Is there no faster way?

Note: the solution needs not be cross-browser, but should preferably not require 3d-party components such as jQuery. The target-device is WebKit on a very slow CPU so I need to keep full control of any reflows.

Emmett answered 14/2, 2011 at 10:31 Comment(2)
possible duplicate of Remove all child elements of a DOM node in JavaScript?Wholewheat
Old question, but please note that instead of erasing the content and then adding new content, you can use the replaceChild function ( developer.mozilla.org/en-US/docs/Web/API/Node/replaceChild ) like this: parentNode.replaceChild(newNode , nodeToBeReplaced);Roley
R
77

If you simply want to replace all children, regarding of the type, why don't you just set its content to '' and then add your code:

container.innerHTML = '';
container.appendChild( newContainerElements );

that would basically remove all the children in the fastest possible way :)

Ringmaster answered 14/2, 2011 at 10:37 Comment(8)
Found this solution myself later when concentrating on optimizing the remove-process. AFAIU the innerHTML-optimization isn't fully cross-browser-safe, and often not mentioned in "remove all children"-questions, but as stated I only care about WebKit and it seems to work for me. :)Emmett
Using innerHTML = "";` doesn't appear to work in either Edge, or apparently IE.Decanal
that is two actionable render view maybe ther is a falster wayShall
Try container.textContent = '' instead of innerHTMLLocke
we can now use container.empty(); instead of container.innerHTML = ''Fillet
@Fillet I can't find any documentation on that. Can you provide a link?Austral
@Austral this was a while ago. i'm guessing i was referring to the empty() jQuery method, instead of a vanilla JS function. (whoops) also just tested..vanilla JS doesn't seem to have an empty() funcitonFillet
𝙨𝙚𝙚 𝙘𝙤𝙧𝙧𝙚𝙘𝙩 2020+ 𝙧𝙚𝙥𝙡𝙖𝙘𝙚𝘾𝙝𝙞𝙡𝙙𝙧𝙚𝙣 𝙖𝙣𝙨𝙬𝙚𝙧Mayoralty
C
64

2020 Update - use the replaceChildren() API!

Replacing all children can now be done with the (cross-browser supported) replaceChildren() API:

container.replaceChildren(...arrayOfNewChildren);

This will do both: a) remove all existing children, and b) append all of the given new children, in one operation.

You can also use this same API to just remove existing children, without replacing them:

container.replaceChildren();

This is supported in Chrome/Edge 86+, Firefox 78+, and Safari 14+. It is fully specified behavior. This is likely to be faster than any other proposed method here, since the removal of old children and addition of new children is done a) without requiring innerHTML, and b) in one step instead of multiple.

Crewelwork answered 23/11, 2020 at 19:15 Comment(6)
Safari doesn't support replaceChildren as of Feb 2021, sourceGoforth
Yes, it does. Did you try it in Safari? It works great. I've raised an issue with MDN to get the compat data corrected.Crewelwork
Also, please don't edit my post to make it less accurate. I've put back Safari 14+.Crewelwork
MDN data has now been corrected to show Safari support: caniuse.com/?search=replacechildrenCrewelwork
replaceChildren() with nothing inside is not working for me on Safari 14.0.3 (macOS). It works with replaceChildren('') or replaceChildren([]). Pretty weirdHouston
Damn, I thought the "..." was just an ellipse, but was the necessary syntax. Without "...", it just add the string of the array itself.Carreon
S
8

Use modern JS! Directly use remove rather than removeChild

while (container.firstChild) {
    container.firstChild.remove();
}

Alternatively:

let child;
while (child = container.firstChild) {
    child.remove();
}
Susy answered 13/8, 2017 at 5:8 Comment(2)
How portable is it?Uchida
This should only be used if backward compatibility is, and will never be, an issue. I don't think of code in terms of "modern", but in terms of "flexibility" and if I must type a few more characters to leave backward compatibility, why not.. good habitChauvin
P
7

It is not directly solving the question but in most cases it is usable and probably one of the more performant ways.

You can swap out the whole node instead of deleting and filling its content.

oldNode.parentElement.replaceChild(newNode, oldNode)
Political answered 6/9, 2019 at 10:0 Comment(1)
This modern one-liner is easier to grasp: oldNode.replaceWith(newNode). replaceWith has very good support.Primogeniture
A
3

A possible alternative where setting innerHTML doesn't work:

while(container.firstChild)
{
  container.removeChild(container.firstChild);
}
container.appendChild(newChild)
Armistice answered 30/5, 2017 at 13:56 Comment(1)
There's (nearly) zero chance innerHTML "doesn't work". Maybe a re-phrasing should be consideredChauvin
O
1

from the top answer, we could also use outerHTML to do it in one line.

container.innerHTML = newContainerElements.outerHTML
Option answered 19/8, 2020 at 7:33 Comment(1)
how didn't i think of that... now instead of cloning an element removing all attributes from it then removing all children from the new element and appending the new one I can just do this: popup.innerHTML = `<picture>${target.parentElement.innerHTML}</picture>`;Ahlgren

© 2022 - 2024 — McMap. All rights reserved.