Can I replace one HTML element with another?
I want to change an <a>
to a <div>
, but I don't want to make the content blank.
From:
<a data-text="text">content</a>
to:
<div data-text="text">content</div>
Any idea?
Can I replace one HTML element with another?
I want to change an <a>
to a <div>
, but I don't want to make the content blank.
From:
<a data-text="text">content</a>
to:
<div data-text="text">content</div>
Any idea?
Use the ChildNode.replaceWith() method to create a new node and replace the old node with the new one. As exemplified in MDN docs:
var parent = document.createElement("div");
var child = document.createElement("p");
parent.appendChild(child);
var span = document.createElement("span");
child.replaceWith(span);
console.log(parent.outerHTML);
// "<div><span></span></div>"
More information is available in this answer.
No. You cannot change the tagName
(nodeName
) of a DOM node.
You can only create a new node of the desired type, copy all attributes (and maybe properties) and move the child nodes. However, this way would still lose inaccessible things like any attached event listeners. This technique is used, for example, when you want to change the type of an input
in IE.
However, there is absolutely no reason to change an a
into a div
; they have completely different semantics (also behaviour and layout).
Basically you create a new element, transfer the attributes to it, then transfer the children and at the end you replace the element with the new one.
I have also provided an example for case sensitive elements like <svg>
. For case sensitive purposes, you shouldn't use innerHTML
. Instead use the while
loop with appendChild
.
function changeTag (node, tag) {
const clone = createElement(tag)
for (const attr of node.attributes) {
clone.setAttributeNS(null, attr.name, attr.value)
}
while (node.firstChild) {
clone.appendChild(node.firstChild)
}
node.replaceWith(clone)
return clone
}
function createElement (tag) {
if (tag === 'svg') {
return document.createElementNS('http://www.w3.org/2000/svg', 'svg')
} else {
return document.createElementNS('http://www.w3.org/1999/xhtml', tag)
}
}
const node1 = document.getElementById('node1')
console.log(node1.outerHTML)
console.log(changeTag(node1, 'a').outerHTML)
const node2 = document.getElementById('node2')
console.log(node2.outerHTML)
console.log(changeTag(node2, 'svg-custom').outerHTML)
<p id="node1" class="x" rel="follow">
Some <b class="a1">bold</b> text
</p>
<svg id="node2" height="150" width="400">
<defs>
<linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" style="stop-color:rgb(255,255,0);stop-opacity:1" />
<stop offset="100%" style="stop-color:rgb(255,0,0);stop-opacity:1" />
</linearGradient>
</defs>
<ellipse cx="200" cy="70" rx="85" ry="55" fill="url(#grad1)" />
</svg>
sure, but why?
var a = document.getElementsByTagName('a');
var src, el, attrs;
for(var i=0,l=a.length;i<l;i++) {
src = a[i];
el = document.createElement('div');
attrs = src.attributes;
for(var j=0,k=attrs.length;j<k;j++) {
el.setAttribute(attrs[j].name, attrs[j].value);
}
el.innerHTML = src.innerHTML;
src.parentNode.replaceChild(el, src);
}
It would be invalid HTML (div
elements do not have a href
attribute) and not act like a link anymore.
However, you could emulate the behaviour using JavaScript:
$('div').on('click', function() {
location.href = $(this).attr('href');
});
But please do not do this. It breaks middle-mouse-clicks (for a new tab) for example.
Here's a simple way to make the div
look and act like an a
tag without having to change the tag type:
Click <div style="display:inline; color:blue; text-decoration:underline; cursor:pointer;"
onclick="window.location='http://example.com/';">here</div>!
Use
var href=$("#aId").attr('href');
$("#aId").replaceWith($("<div"+href+">" + $("#aId").innerHTML + "</div>"));
Here's a way to change the tag of an element:
// Just provide the element and the new tag
function changeTag(el, newTag) {
var outerHTML = el.outerHTML // Get the outerHTML of the element
var tag = el.tagName // Get the tag of the outerHTML
var r = new RegExp(tag, 'i') // Prepare a RegExp to replace the old tag with the new tag
outerHTML = outerHTML.replace(r, newTag) // Replace it
el.outerHTML = outerHTML // Set the outerHTML of the element
}
<span>Span 1</span> -- <span>Span 2</span>
<br>
<button onclick="changeTag(document.querySelector('span'), 'div')">
Change tag
</button>
const atts = Array.prototype.slice.call(elem.attributes)
elem.outerHTML = `<div ${atts.map(
attr => (attr.name + '="' + attr.value + '"')
).join(' ')}>${elem.innerHTML}</div>`
This solution will convert your tag name and preserve all attributes without the necessity to remove and add elements from and to the DOM, by yourself. The browser will handle that for you, so you have to reload the element from the DOM to access it after conversion.
let elem = document.getElementById("test")
const tagName = 'div'
const atts = Array.prototype.slice.call(elem.attributes)
elem.outerHTML = `<${tagName} ${atts.map(
attr => (attr.name + '="' + attr.value + '"')
).join(' ')}>${elem.innerHTML}</${tagName}>`
elem = document.getElementById("test") // reload required
console.log(elem.outerHTML)
<span id="test" data-test="123">I want to be a div.</span>
elem.outerHTML = `<div id="test">${elem.innerHTML}</div>`
This one-liner will do it, but remember that elem
will point to the old element, just like in the above solution.
let elem = document.getElementById("test")
const tagName = 'div'
elem.outerHTML = `<${tagName} id="test">${elem.innerHTML}</${tagName}>`
elem = document.getElementById("test") // reload required
console.log(elem.outerHTML)
<span id="test">I want to be a div.</span>
With these methods, you always have to re-load the object from the DOM to continue to work with it, since the browser will create a new DOM element and place it for you under the hood.