218

I am looking to replace an element in the DOM.
For example, there is an <a> element that I want to replace with a <span> instead.

How would I go and do that?

vsync
  • 118,978
  • 58
  • 307
  • 400
omg
  • 136,412
  • 142
  • 288
  • 348

10 Answers10

228

by using replaceChild():

<html>
<head>
</head>
<body>
  <div>
    <a id="myAnchor" href="http://www.stackoverflow.com">StackOverflow</a>
  </div>
<script type="text/JavaScript">
  var myAnchor = document.getElementById("myAnchor");
  var mySpan = document.createElement("span");
  mySpan.innerHTML = "replaced anchor!";
  myAnchor.parentNode.replaceChild(mySpan, myAnchor);
</script>
</body>
</html>
steal3rd
  • 108
  • 10
Bjorn
  • 69,215
  • 39
  • 136
  • 164
  • 7
    this example wouldn't work. You should put the script block at the end of the body to make it work. Furthermore, just for fun: try adding the line [alert(myAnchor.innerHTML)] after the operation. – KooiInc May 10 '09 at 08:27
  • Theres a spelling mistake with StackOverflow in the anchor innerText – rahul May 11 '09 at 11:50
  • 8
    what if it is root html element – lisak Jun 05 '11 at 18:01
  • Thank you @Bjorn Tipling. I've created a follow up question on how to add an id and a function to the replaced element, here: http://stackoverflow.com/questions/15670261/how-to-replace-dom-element-with-js-and-include-an-id-and-a-js-function – JDelage Mar 27 '13 at 21:58
148

A.replaceWith(span) - No parent needed

Generic form:

target.replaceWith(element)

Way better/cleaner than the previous method.

For your use case:

A.replaceWith(span)

Advanced usage

  1. You can pass multiple values (or use spread operator ...).
  2. Any string value will be added as a text element.

Examples:

// Initially [child1, target, child3]

target.replaceWith(span, "foo")     // [child1, span, "foo", child3]

const list = ["bar", span]
target.replaceWith(...list, "fizz")  // [child1, "bar", span, "fizz", child3]

Safely handling null target

If your target has a chance to be null, you can consider using the newish ?. optional chaining operator. Nothing will happen if target doesn't exist. Read more here.

target?.replaceWith?.(element)

Related DOM methods

  1. Read More - child.before and child.after
  2. Read More - parent.prepend and parent.append

Mozilla Docs

Supported Browsers - 97% Nov '22

Gibolt
  • 42,564
  • 15
  • 187
  • 127
  • 13
    Not supported in IE11 or Edge 14 (now: 2016-11-16). – jor Nov 16 '16 at 17:06
  • 4
    Try using Google's Closure or another transpiler to convert to ES5. You shouldn't be writing old code based on browser support, if you have a better, more maintainable option – Gibolt Jan 12 '17 at 03:37
  • 1
    Thus transpiling. You can optimize, minify, and down-convert all in one. Check it out: https://developers.google.com/closure/compiler/ – Gibolt Feb 28 '17 at 06:12
  • 5
    I think if the choice is between use code that works on all browsers I'm trying to support, or re-tool your whole build process to use Closure, I would pick use code that works on all browsers that I'm trying to support. – cdmckay Mar 16 '17 at 02:34
  • 5
    @jor I kinda agree to support as many browsers as possible, but I refuse to remade my code just because IE or Edge are incomplete or just "want to be different". There are standards, if they don't follow them and a few people support it, that is their problem, that don't have to affect us as web developers. – David Tabernero M. Jul 25 '17 at 11:05
  • 1
    @Davdriver: of course, but the current global support is only 69%: http://caniuse.com/#search=replaceWith – jor Jul 26 '17 at 07:58
  • `replaceWith` has nothing to do with ES5. It is defined by the WHATWG DOM spec. – Quentin Oct 20 '17 at 17:56
  • 3
    Global support is now at 72%, 80% in U.S. as of Oct 2017 – Gibolt Oct 20 '17 at 19:58
  • My gulp process didn't transpile this function into something more browser friendly. – The Onin Dec 29 '17 at 07:12
  • It’s super neat, bit of a bummer that as of January 2019 Safari still offers no support of `replaceWith`. Unless you’re using transpilers/polyfills, I would stick with [`replaceChild`](https://developer.mozilla.org/en-US/docs/Web/API/Node/replaceChild) in meantime. – Anton Strogonoff Jan 27 '19 at 04:54
  • 1
    Safari and all major modern browsers now support this in Apr 2020. – Gibolt May 08 '20 at 18:30
  • 1
    It is not my concern that [replaceWith](https://developer.mozilla.org/en-US/docs/Web/API/ChildNode/replaceWith) is not supported in Internet Explorer I dropped support for it 11 years ago (IE8). Note that I'm still supporting current minus 10 on browsers that auto update can be turned off and this still works fine. – AaA Jun 19 '20 at 02:31
68
var a = A.parentNode.replaceChild(document.createElement("span"), A);

a is the replaced A element.

Kamarey
  • 10,832
  • 7
  • 57
  • 70
7

This question is very old, but I found myself studying for a Microsoft Certification, and in the study book it was suggested to use:

oldElement.replaceNode(newElement)

I looked it up and it seems to only be supported in IE. Doh..

I thought I'd just add it here as a funny side note ;)

Zeliax
  • 4,987
  • 10
  • 51
  • 79
3

I had a similar issue and found this thread. Replace didn't work for me, and going by the parent was difficult for my situation. Inner Html replaced the children, which wasn't what I wanted either. Using outerHTML got the job done. Hope this helps someone else!

currEl = <div>hello</div>
newElem = <span>Goodbye</span>
currEl.outerHTML = newElem
# currEl = <span>Goodbye</span>
Sean
  • 2,412
  • 3
  • 25
  • 31
3

You can replace an HTML Element or Node using Node.replaceWith(newNode).

This example should keep all attributes and childs from origin node:

const links = document.querySelectorAll('a')

links.forEach(link => {
  const replacement = document.createElement('span')
  
  // copy attributes
  for (let i = 0; i < link.attributes.length; i++) {
     const attr = link.attributes[i]
     replacement.setAttribute(attr.name, attr.value)
  }
  
  // copy content
  replacement.innerHTML = link.innerHTML
  
  // or you can use appendChild instead
  // link.childNodes.forEach(node => replacement.appendChild(node))

  link.replaceWith(replacement)
})

If you have these elements:

<a href="#link-1">Link 1</a>
<a href="#link-2">Link 2</a>
<a href="#link-3">Link 3</a>
<a href="#link-4">Link 4</a>

After running above codes, you will end up with these elements:

<span href="#link-1">Link 1</span>
<span href="#link-2">Link 2</span>
<span href="#link-3">Link 3</span>
<span href="#link-4">Link 4</span>
Nurul Huda
  • 1,438
  • 14
  • 12
  • The answers given assume a static DOM. What if the DOM has been modified, e.g., via an onload script? – Page Notes Dec 20 '20 at 00:48
  • just make sure that the `document.querySelectorAll('a')` is executed after the DOM has been modified or generated. – Nurul Huda Dec 22 '20 at 15:14
2

You can use replaceChild on the parent of the target element after creating your new element (createElement):

const newElement = document.createElement(/*...*/);
const target = document.getElementById("my-table");
target.parentNode.replaceChild(newElement, target);

If your starting point for the new element is HTML, you can use insertAdjacentHTML and then removeChild on the parent (or remove on the element itself, in modern environments):

const target = document.getElementById("my-table");
target.insertAdjacentHTML("afterend", theHTMLForTheNewElement);
target.parentNode.removeChild(target); // Or: `target.remove()`
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
2

Best way to do it. No parents need. Just use Element.outerHTML = template;

// Get the current element
var currentNode = document.querySelector('#greeting');

// Replace the element
currentNode.outerHTML =
    '<div id="salutations">' +
        '<h1>Hi, universe!</h1>' +
        '<p>The sun is always shining!</p>' +
    '</div>';
Vitold
  • 21
  • 2
-1

Example for replacing LI elements

function (element) {
    let li = element.parentElement;
    let ul = li.parentNode;   
    if (li.nextSibling.nodeName === 'LI') {
        let li_replaced = ul.replaceChild(li, li.nextSibling);
        ul.insertBefore(li_replaced, li);
    }
}
klobastov
  • 44
  • 5
-1

Given the already proposed options the easiest solution without finding a parent:

var parent = document.createElement("div");
var child = parent.appendChild(document.createElement("a"));
var span = document.createElement("span");

// for IE
if("replaceNode" in child)
  child.replaceNode(span);

// for other browsers
if("replaceWith" in child)
  child.replaceWith(span);

console.log(parent.outerHTML);