jQuery: how to change tag name?

JavascriptJqueryHtmlDomDhtml

Javascript Problem Overview


jQuery: how to change tag name?

For example:

<tr>
    $1
</tr>

I need

<div>
    $1
</div>

Yes, I can

  1. Create DOM element <div>
  2. Copy tr content to div
  3. Remove tr from dom

But can I make it directly?

PS:

    $(tr).get(0).tagName = "div"; 

results in DOMException.

Javascript Solutions


Solution 1 - Javascript

You can replace any HTML markup by using jQuery's .replaceWith() method.

example: http://jsfiddle.net/JHmaV/

Ref.: .replaceWith

If you want to keep the existing markup, you could use code like this:

$('#target').replaceWith('<newTag>' + $('#target').html() +'</newTag>')

Solution 2 - Javascript

No, it is not possible according to W3C specification: "tagName of type DOMString, readonly"

http://www.w3.org/TR/DOM-Level-2-Core/core.html

Solution 3 - Javascript

Where the DOM renameNode() Method?

Today (2014) no browser understand the new DOM3 renameNode method (see also W3C) check if run at your bowser: http://jsfiddle.net/k2jSm/1/

So, a DOM solution is ugly and I not understand why (??) jQuery not implemented a workaround?

pure DOM algorithm

  1. createElement(new_name)
  2. copy all content to new element;
  3. replace old to new by replaceChild()

is something like this,

function rename_element(node,name) {
    var renamed = document.createElement(name); 
    foreach (node.attributes as a) {
    	renamed.setAttribute(a.nodeName, a.nodeValue);
    }
    while (node.firstChild) {
    	renamed.appendChild(node.firstChild);
    }
    return node.parentNode.replaceChild(renamed, node);
}

... wait review and jsfiddle ...

jQuery algorithm

The @ilpoldo algorithm is a good start point,

   $from.replaceWith($('<'+newname+'/>').html($from.html()));

As others commented, it need a attribute copy ... wait generic ...

specific for class, preserving the attribute, see http://jsfiddle.net/cDgpS/

See also https://stackoverflow.com/a/9468280/287948

Solution 4 - Javascript

The above solutions wipe out the existing element and re-create it from scratch, destroying any event bindings on children in the process.

short answer: (loses <p/>'s attributes)

$("p").wrapInner("<div/>").children(0).unwrap();

longer answer: (copies <p/>'s attributes)

$("p").each(function (o, elt) {
  var newElt = $("<div class='p'/>");
  Array.prototype.slice.call(elt.attributes).forEach(function(a) {
    newElt.attr(a.name, a.value);
  });
  $(elt).wrapInner(newElt).children(0).unwrap();
});

fiddle with nested bindings

It would be cool to copy any bindings from the

at the same time, but getting current bindings didn't work for me.

Solution 5 - Javascript

To preserve the internal content of the tag you can use the accessor .html() in conjunction with .replaceWith()

forked example: http://jsfiddle.net/WVb2Q/1/

Solution 6 - Javascript

Inspired by ericP answer, formatted and converted to jQuery plugin:

$.fn.replaceWithTag = function(tagName) {
    var result = [];
    this.each(function() {
        var newElem = $('<' + tagName + '>').get(0);
        for (var i = 0; i < this.attributes.length; i++) {
            newElem.setAttribute(
                this.attributes[i].name, this.attributes[i].value
            );
        }
        newElem = $(this).wrapInner(newElem).children(0).unwrap().get(0);
        result.push(newElem);
    });
    return $(result);
};

Usage:

$('div').replaceWithTag('span')

Solution 7 - Javascript

Working pure DOM algorithm

function rename_element(node, name) {
    let renamed = document.createElement(name);

    Array.from(node.attributes).forEach(attr => {
        renamed.setAttribute(attr.name, attr.value);        
    })
    while (node.firstChild) {
        renamed.appendChild(node.firstChild);
    }
    node.parentNode.replaceChild(renamed, node);
    return renamed;
}

Solution 8 - Javascript

You could go a little basic. Works for me.

var oNode = document.getElementsByTagName('tr')[0];

var inHTML = oNode.innerHTML;
oNode.innerHTML = '';
var outHTML = oNode.outerHTML;
outHTML = outHTML.replace(/tr/g, 'div');
oNode.outerHTML = outHTML;
oNode.innerHTML = inHTML;

Solution 9 - Javascript

To replace the internal contents of multiple tags, each with their own original content, you have to use .replaceWith() and .html() differently:

http://jsfiddle.net/kcrca/VYxxG/

Solution 10 - Javascript

JS to change the tag name

/**
 * This function replaces the DOM elements's tag name with you desire
 * Example:
 *        replaceElem('header','ram');
 *        replaceElem('div.header-one','ram');
 */
function replaceElem(targetId, replaceWith){
  $(targetId).each(function(){
    var attributes = concatHashToString(this.attributes);
    var replacingStartTag = '<' + replaceWith + attributes +'>';
    var replacingEndTag = '</' + replaceWith + '>';
    $(this).replaceWith(replacingStartTag + $(this).html() + replacingEndTag);
  });
}
replaceElem('div','span');

/**
 * This function concats the attributes of old elements
 */
function concatHashToString(hash){
  var emptyStr = '';
  $.each(hash, function(index){
    emptyStr += ' ' + hash[index].name + '="' + hash[index].value + '"';
  });
  return emptyStr;
}

Related fiddle is in this link

Solution 11 - Javascript

Simply changing the property values won't do it (as others have said, some HTMLElement properties are read-only; also some hold prototypal context to more primitive elements). The closest thing you can get to mimicking the DOM API is to mimic also the process of prototypal inheritance in JavaScript.

'Setting' on an object's prototype via __proto__ is generally frowned upon. Also, you might consider why you think you need to duplicate the entire DOM element in the first place. But here goes:

// Define this at whatever scope you'll need to access it
// Most of these kinds of constructors are attached to the `window` object

window.HTMLBookElement = function() {

  function HTMLBookElement() {
    var book = document.createElement('book');
    book.__proto__ = document.createElement('audio');
    return book;
  }

  return new HTMLBookElement();

}

// Test your new element in a console (I'm assuming you have Chrome)

var harryPotter = new HTMLBookElement();

// You should have access to your new `HTMLBookElement` API as well as that
// of its prototype chain; since I prototyped `HTMLAudioElement`, you have 
// some default properties like `volume` and `preload`:

console.log(harryPotter);         // should log "<book></book>"
console.log(harryPotter.volume);  // should log "1"
console.log(harryPotter.preload); // should log "auto"

All DOM elements work this way. For example: <div></div> is produced by HTMLDivElement, which extends HTMLElement, which in turn extends Element, which in turn extends Object.

Solution 12 - Javascript

Since replaceWith() didn't work for me on an element basis (maybe because I used it inside map()), I did it by creating a new element and copying the attributes as needed.

$items = $('select option').map(function(){

  var
    $source = $(this),
    $copy = $('<li></li>'),
    title = $source.text().replace( /this/, 'that' );

  $copy
    .data( 'additional_info' , $source.val() )
    .text(title);

  return $copy;
});

$('ul').append($items);

Solution 13 - Javascript

Take him by the word

Taken the Question by Word "how to change tag name?" I would suggest this solution:
If it makes sense or not has to be decided case by case.

My example will "rename" all a-Tags with hyperlinks for SMS with span tags. Maintaining all attributes and content:

$('a[href^="sms:"]').each(function(){
  var $t=$(this);
  var $new=$($t.wrap('<div>')
    .parent()
		.html()
		.replace(/^\s*<\s*a/g,'<span')
		.replace(/a\s*>\s*$/g,'span>')
		).attr('href', null);
  $t.unwrap().replaceWith($new);
});

As it does not make any sense to have a span tag with an href attribute I remove that too. Doing it this way is bulletproof and compatible with all browsers that are supported by jquery. There are other ways people try to copy all the Attributes to the new Element, but those are not compatible with all browsers.

Although I think it is quite expensive to do it this way.

Solution 14 - Javascript

Jquery plugin to make "tagName" editable :

(function($){
	var $newTag = null;
	$.fn.tagName = function(newTag){
		this.each(function(i, el){
			var $el = $(el);
			$newTag = $("<" + newTag + ">");
            
			// attributes
			$.each(el.attributes, function(i, attribute){
				$newTag.attr(attribute.nodeName, attribute.nodeValue);
			});
			// content
			$newTag.html($el.html());
			
			$el.replaceWith($newTag);
		});
		return $newTag;
	};
})(jQuery);

See : http://jsfiddle.net/03gcnx9v/3/

Solution 15 - Javascript

Yet another script to change the node name

function switchElement() {
  $element.each(function (index, oldElement) {
    let $newElement = $('<' + nodeName + '/>');
    _.each($element[0].attributes, function(attribute) {
      $newElement.attr(attribute.name, attribute.value);
    });
    $element.wrapInner($newElement).children().first().unwrap();
  });
}

http://jsfiddle.net/rc296owo/5/

It will copy over the attributes and inner html into a new element and then replace the old one.

Solution 16 - Javascript

$(function(){
    $('#switch').bind('click', function(){
        $('p').each(function(){
        	$(this).replaceWith($('<div/>').html($(this).html()));
        });
    });
});

p {
    background-color: red;
}

div {
    background-color: yellow;
}

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>Hello</p>
<p>Hello2</p>
<p>Hello3</p>
<button id="switch">replace</button>

Solution 17 - Javascript

You can use this function

var renameTag  = function renameTag($obj, new_tag) {
    var obj = $obj.get(0);
    var tag = obj.tagName.toLowerCase();
    var tag_start = new RegExp('^<' + tag);
    var tag_end = new RegExp('<\\/' + tag + '>$');
    var new_html = obj.outerHTML.replace(tag_start, "<" + new_tag).replace(tag_end, '</' + new_tag + '>');
    $obj.replaceWith(new_html);
};

ES6

const renameTag = function ($obj, new_tag) {
    let obj = $obj.get(0);
    let tag = obj.tagName.toLowerCase();
    let tag_start = new RegExp('^<' + tag);
    let tag_end = new RegExp('<\\/' + tag + '>$');
    let new_html = obj.outerHTML.replace(tag_start, "<" + new_tag).replace(tag_end, '</' + new_tag + '>');
    $obj.replaceWith(new_html);
};

Sample code

renameTag($(tr),'div');

Solution 18 - Javascript

Try this one also. in this example we can also have attributes of the old tag in new tag

var newName = document.querySelector('.test').outerHTML.replaceAll('h1', 'h2');
document.querySelector('.test').outerHTML = newName;

<h1 class="test">Replace H1 to H2</h1>

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionpuchuView Question on Stackoverflow
Solution 1 - JavascriptjAndyView Answer on Stackoverflow
Solution 2 - JavascriptggarberView Answer on Stackoverflow
Solution 3 - JavascriptPeter KraussView Answer on Stackoverflow
Solution 4 - JavascriptericPView Answer on Stackoverflow
Solution 5 - JavascriptilpoldoView Answer on Stackoverflow
Solution 6 - JavascriptDmitriy SintsovView Answer on Stackoverflow
Solution 7 - JavascriptPascal Pixel RigauxView Answer on Stackoverflow
Solution 8 - JavascriptCoryView Answer on Stackoverflow
Solution 9 - Javascriptuser856027View Answer on Stackoverflow
Solution 10 - JavascriptillusionistView Answer on Stackoverflow
Solution 11 - JavascriptBenny NightingaleView Answer on Stackoverflow
Solution 12 - JavascriptWoodrowShigeruView Answer on Stackoverflow
Solution 13 - JavascriptHannes MorgensternView Answer on Stackoverflow
Solution 14 - JavascriptcedrikView Answer on Stackoverflow
Solution 15 - JavascriptBertyView Answer on Stackoverflow
Solution 16 - JavascriptIfeanyi ChukwuView Answer on Stackoverflow
Solution 17 - JavascriptSarath AkView Answer on Stackoverflow
Solution 18 - JavascriptAbdulAhmad MatinView Answer on Stackoverflow