11

I want to know if we can change tag name in a tag rather than its content. I have this content

<wns id="93" onclick="wish(id)">...</wns>    

In the wish function I want to change it to

<lmn id="93" onclick="wish(id)">...</lmn>

I tried this way:

document.getElementById("99").innerHTML = document.getElementById("99").replace(/wns/g,"lmn");

but it does not work.

Please note that I just want to alter that specific tag with specific id rather than every wns tag.

tom
  • 21,844
  • 6
  • 43
  • 36
Mohan Krishna
  • 123
  • 1
  • 2
  • 9
  • 1
    First of all, those tagnames are not valid HTML, and no, you can't change a tagname in HTML (you can however replace it). – adeneo Feb 26 '13 at 10:29
  • Perhaps this might help you: http://stackoverflow.com/questions/918792/use-jquery-to-change-an-html-tag – Francisco Paulo Feb 26 '13 at 10:31

6 Answers6

32

You can't change the tag name of an existing DOM element; instead, you have to create a replacement and then insert it where the element was.

The basics of this are to move the child nodes into the replacement and similarly to copy the attributes. So for instance:

var wns = document.getElementById("93");
var lmn = document.createElement("lmn");
var index;

// Copy the children
while (wns.firstChild) {
    lmn.appendChild(wns.firstChild); // *Moves* the child
}

// Copy the attributes
for (index = wns.attributes.length - 1; index >= 0; --index) {
    lmn.attributes.setNamedItem(wns.attributes[index].cloneNode());
}

// Replace it
wns.parentNode.replaceChild(lmn, wns);

Live Example: (I used div and p rather than wns and lmn, and styled them via a stylesheet with borders so you can see the change)

document.getElementById("theSpan").addEventListener("click", function() {
  alert("Span clicked");
}, false);

document.getElementById("theButton").addEventListener("click", function() {

  var wns = document.getElementById("target");
  var lmn = document.createElement("p");
  var index;

  // Copy the children
  while (wns.firstChild) {
    lmn.appendChild(wns.firstChild); // *Moves* the child
  }

  // Copy the attributes
  for (index = wns.attributes.length - 1; index >= 0; --index) {
    lmn.attributes.setNamedItem(wns.attributes[index].cloneNode());
  }

  // Insert it
  wns.parentNode.replaceChild(lmn, wns);
}, false);
div {
  border: 1px solid green;
}
p {
  border: 1px solid blue;
}
<div id="target" foo="bar" onclick="alert('hi there')">
  Content before
  <span id="theSpan">span in the middle</span>
  Content after
</div>
<input type="button" id="theButton" value="Click Me">

See this gist for a reusable function.


Side note: I would avoid using id values that are all digits. Although they're valid in HTML (as of HTML5), they're invalid in CSS and thus you can't style those elements, or use libraries like jQuery that use CSS selectors to interact with them.

Web_Designer
  • 72,308
  • 93
  • 206
  • 262
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • 3
    Actually you **can**! Dirty example: `tag.outerHTML = "<" + newName + ">" + tag.innerHTML + "" + newName + ">";` – Bitterblue Sep 23 '14 at 06:44
  • 5
    @Bitterblue: Nope. :-) That creates a *new* element and swaps it in for the old one. And just like other ways you do that, you lose event handlers, you lose expandos, any outstanding references to the object point to the *old* element, etc. Example: http://jsbin.com/kucuf/1 In the normal case, your code above is effectively the same as `var newElement = document.createElement(newName); newElement.innerHTML = element.innerHTML; element.parentNode.replaceChild(element, newElement);` – T.J. Crowder Sep 23 '14 at 07:43
  • 3
    @T.J.Crowder this seems like the best answer, but why didn't you just use replaceChild instead of the last insert and remove methods? – shuji Oct 05 '15 at 19:49
  • `function changeTag(el, newTagName = "div") { var newEl = document.createElement(newTagName); [...el.children].forEach(o => newEl.appendChild(o)); [...el.attributes].forEach(o => newEl.attributes.setNamedItem(o.cloneNode())); el.parentNode.replaceChild(newEl, el); return newEl; }` – 7vujy0f0hy Apr 27 '17 at 05:52
23
var element = document.getElementById("93");
element.outerHTML = element.outerHTML.replace(/wns/g,"lmn");

FIDDLE

Arad Alvand
  • 8,607
  • 10
  • 51
  • 71
adeneo
  • 312,895
  • 29
  • 395
  • 388
  • How's the support for `outerHTML` in the wild these days? – T.J. Crowder Feb 26 '13 at 10:35
  • @T.J.Crowder - actually checked this on [MDN](https://developer.mozilla.org/en-US/docs/DOM/element.outerHTML) myself, and does'nt seem that bad! – adeneo Feb 26 '13 at 10:36
  • 4
    That's cool. Making the round-trip through markup will remove any event handlers on the descendant elements, though, which is less than ideal. – T.J. Crowder Feb 26 '13 at 10:38
  • @T.J.Crowder - Yeah, it's the easy way for browsers that support it, but you loose everything that's not explicitly set in the markup, like event handlers on descending elements! – adeneo Feb 26 '13 at 10:40
  • I checked it in chrome n firefox, it does work.. thanks a million :) – Mohan Krishna Feb 26 '13 at 10:42
  • 2
    Amazing. I'd always thought `outerHTML` was a getter only, and couldn't be set. Revelatory! – Barney Feb 26 '13 at 10:45
  • 8
    Yeah but what if you have "wns" in the innerhtml of the tag? – Nick Manning Jun 27 '14 at 18:27
  • @NickManning - The OP didn't, but then you could do something like `.replace(/ – adeneo Jun 27 '14 at 19:46
  • 1
    I'd *at least* use word boundary markers on the replacement, and a big old caveat that this *replaces* the element would also be a good idea. :-) – T.J. Crowder Sep 23 '14 at 07:47
  • Nice, but not ideal, this changes every occurrence of the string `wms` throughout the HTML. – Arad Alvand Mar 15 '21 at 08:09
  • It not reaally works, it triggers. Try to change an attribute at the same time. It will not be applied. This is because outerHTML is a snapshot from `getElementById`. After the script has processed the browser will trigger a rerendering and after that you will be able to access it again with it's new tagname, so it depends if this solutions fits for you or not, for me it doesn't. – René Baudisch Apr 12 '21 at 16:57
  • 4
    If you have `wns` in content, it will be replaced. That's not funny. – Andrei May 25 '21 at 16:18
  • Just use the full regex: `Element.outerHTML = Element.outerHTML.replace(/^$/, "")` – netizen Jun 30 '23 at 15:10
9

There are several problems with your code:

  1. HTML element IDs must start with an alphabetic character.
  2. document.getElementById("99").replace(/wns/g,"lmn") is effectively running a replace command on an element. Replace is a string method so this causes an error.
  3. You're trying to assign this result to document.getElementById("99").innerHTML, which is the HTML inside the element (the tags, attributes and all are part of the outerHTML).
  4. You can't change an element's tagname dynamically, since it fundamentally changes it's nature. Imagine changing a textarea to a select… There are so many attributes that are exclusive to one, illegal in the other: the system cannot work!

What you can do though, is create a new element, and give it all the properties of the old element, then replace it:

<wns id="e93" onclick="wish(id)">
    ...
</wns>

Using the following script:

// Grab the original element
var original    = document.getElementById('e93');
// Create a replacement tag of the desired type
var replacement = document.createElement('lmn');

// Grab all of the original's attributes, and pass them to the replacement
for(var i = 0, l = original.attributes.length; i < l; ++i){
    var nodeName  = original.attributes.item(i).nodeName;
    var nodeValue = original.attributes.item(i).nodeValue;

    replacement.setAttribute(nodeName, nodeValue);
}

// Persist contents
replacement.innerHTML = original.innerHTML;

// Switch!
original.parentNode.replaceChild(replacement, original);

Demo here: http://jsfiddle.net/barney/kDjuf/

close
  • 77
  • 1
  • 8
Barney
  • 16,181
  • 5
  • 62
  • 76
1

You can replace the whole tag using jQuery

var element = $('#99');
element.replaceWith($(`<lmn id="${element.attr('id')}">${element.html()}</lmn>`));
Nice18
  • 476
  • 2
  • 12
cioddi
  • 763
  • 4
  • 12
0

[...document.querySelectorAll('.example')].forEach(div => {
  div.outerHTML =
  div.outerHTML
    .replace(/<div/g, '<span')
    .replace(/<\/div>/g, '</span>')
})
<div class="example">Hello,</div>
<div class="example">world!</div>
Nice18
  • 476
  • 2
  • 12
-2

You can achieve this by using JavaScript or jQuery.

We can delete the DOM Element(tag in this case) and recreate using .html or .append menthods in jQuery.

$("#div-name").html("<mytag>Content here</mytag>");

OR

$("<mytag>Content here</mytag>").appendTo("#div-name");
Aleem
  • 17
  • 5