JavaScriptDOM and events

Node.cloneNode()

Creates a copy of a node. With the argument true, it also copies all the content, meaning every element and text inside.

Returns
A new node, a copy of the original, not yet attached to the document.
On this page

Example

#
JavaScript
const list = document.querySelector('#courses')
const original = list.querySelector('.course')

const deep = original.cloneNode(true)
const shallow = original.cloneNode()

deep.querySelector('strong').textContent = 'CSS'
list.append(deep)

console.log(list.children.length)
console.log(original.textContent)
console.log(deep.textContent)
console.log(shallow, shallow.childNodes.length)
Console
2
HTML $49
CSS $49
<li class="course"> 0

Definition and usage

#

The cloneNode() method returns a copy of an element or other node. The copy has the same attributes, classes, and inline styles, but it’s a new, independent object: it isn’t in the document yet, and changes to the copy don’t affect the original. To show it, insert it, for example with append().

The deep argument decides on the content. cloneNode(true) copies the element together with all descendants and text. cloneNode() with no argument (or with false) creates a shallow copy: just the element with its attributes, but empty inside. In practice, you almost always need true.

The copy doesn’t inherit event handlers added with addEventListener(), or custom properties attached to the element object in JavaScript. Attributes are copied, though, including id, so after inserting the copy into the page there would be two elements with the same identifier. Change or remove it before inserting.

Cloning is often paired with the <template> element: you copy its content (template.content) with cloneNode(true), fill it with data, and insert it into the page. It’s a convenient way to handle repeating fragments, such as course cards.

Syntax

#
Syntax
node.cloneNode()
node.cloneNode(deep)

Parameters

#
  • deep

    optional, boolean

    true copies the node together with all its content. Defaults to false, meaning a copy with no children.

More examples

#
Event handlers aren’t copied
JavaScript
const button = document.querySelector('#hint')
button.addEventListener('click', () => console.log('Hint from the original'))

const copy = button.cloneNode(true)
copy.id = 'hint-copy'
document.querySelector('#toolbar').append(copy)

copy.click()
button.click()
console.log(copy.id, copy.className)
Console
Hint from the original
hint-copy btn

Clicking the copy prints nothing, since cloneNode() carries over attributes, but not handlers added with addEventListener(). The copy also got a new id, so the identifier isn’t duplicated.

Course cards from a <template>
JavaScript
const template = document.querySelector('#card-template')
const cards = document.querySelector('#cards')
const courses = [
  { title: 'HTML', points: 120 },
  { title: 'CSS', points: 90 }
]

for (const course of courses) {
  const card = template.content.cloneNode(true)
  card.querySelector('h3').textContent = course.title
  card.querySelector('.points').textContent = `${course.points} pts`
  cards.append(card)
}

console.log(cards.children.length)
console.log(cards.querySelector('.card:last-child h3').textContent)
Console
2
CSS

The <template> content isn’t displayed on the page, it only serves as a blueprint. Every cloneNode(true) gives a fresh copy, which we fill with different data.

Browser support

#

Widely available

Works in all modern browsers, phones included. You can use it without worry.

  • Chrome
  • Edge
  • Firefox
  • Safari

Good practices

#
  • Almost always call cloneNode(true). Without the argument you get an empty element, with no text or children.
  • After cloning, change or remove the id, so the page doesn’t end up with two elements sharing the same identifier.
  • Attach event handlers to the copy again, or handle clicks on a shared parent (event delegation).

Related entries

#

Spotted a mistake or missing an example? Write to us.