JavaScript DOM: Cloning Elements

JavaScript DOM: Cloning Elements

Cloning elements in the JavaScript Document Object Model (DOM) means creating a copy of an existing node. This is especially useful when you want to duplicate content dynamically, such as repeating a card, duplicating form fields, or creating templates on the fly. Cloning allows you to reuse elements without writing the HTML again, making your web pages more interactive and flexible.

The key method for cloning nodes is cloneNode(). This method can create either a shallow or deep copy of an element. A shallow copy duplicates only the element itself, while a deep copy includes the element and all its child nodes. Understanding these concepts is fundamental to effectively duplicating elements and managing dynamic content in your pages.

Basic Cloning with cloneNode(false)

The simplest form of cloning is a shallow clone, where only the element itself is duplicated, but none of its child elements or text content are copied. This can be done by passing false as an argument to cloneNode().

Here’s a simple example where a div is cloned without any children or inner text:

<!DOCTYPE html>
<html>
<head>
  <title>Shallow Cloning</title>
</head>
<body>

  <div id="original" style="border: 1px solid black; padding: 10px;">
    Hello, I am the original div!
  </div>

  <script>

    const original = document.getElementById('original');
    const shallowClone = original.cloneNode(false);

    shallowClone.style.border = '2px dashed red';
    shallowClone.textContent = 'I am a shallow clone (no children, no original text)';

    document.body.appendChild(shallowClone);

  </script>

</body>
</html>

In this example, the original div is cloned without its text content because cloneNode(false) only copies the element node. The clone’s border color is changed to red, and new text is added. This illustrates how shallow cloning gives you a blank shell of the element to modify as you wish.

Deep Cloning with cloneNode(true)

Deep cloning is when the element and all of its children (including text nodes and nested elements) are copied. This is done by passing true to cloneNode(). This method duplicates the entire subtree of the node.

Let’s look at an example with a nested list to show deep cloning in action:

<!DOCTYPE html>
<html>
<head>
  <title>Deep Cloning</title>
</head>
<body>

  <ul id="originalList" style="border: 1px solid blue; padding: 10px;">
    <li>Cat</li>
    <li>Dog</li>
    <li>Bird
      <ul>
        <li>Parrot</li>
        <li>Canary</li>
      </ul>
    </li>
  </ul>

  <script>

    const originalList = document.getElementById('originalList');
    const deepClone = originalList.cloneNode(true);

    deepClone.style.border = '2px dotted green';
    deepClone.id = 'clonedList';

    document.body.appendChild(deepClone);

  </script>

</body>
</html>

This code copies the entire list with all its nested items. The clone’s border style and ID are changed to differentiate it from the original. Deep cloning ensures the whole structure and content are duplicated exactly.

Cloning Elements and Adding Them to the DOM

Cloning is often combined with inserting the clone somewhere in the document to create dynamic interfaces. After creating a clone, you can use methods like appendChild or insertBefore to place it on the page.

Here’s an example where a button clones a paragraph when clicked:

<!DOCTYPE html>
<html>
<head>
  <title>Clone and Insert</title>
</head>
<body>

  <p id="para" style="font-size: 18px;">I am the original paragraph.</p>
  <button id="cloneBtn">Clone Paragraph</button>

  <script>

    const para = document.getElementById('para');
    const button = document.getElementById('cloneBtn');

    button.addEventListener('click', () => {

      const clone = para.cloneNode(true);
      clone.style.color = 'purple';
      clone.textContent += ' (I am a clone!)';

      document.body.appendChild(clone);

    });

  </script>

</body>
</html>

Clicking the button clones the paragraph, colors the clone purple, and appends it below the original. This example highlights how cloning can be used for interactive features.

Cloning Form Elements and Their Values

When you clone a form element using cloneNode(true), the browser creates a deep copy of the form — including all of its child nodes and their current state. This means the clone will include user-entered values, checked checkboxes, and other live updates to the form inputs, just as they appear at the moment of cloning.

Here’s an example showing how form fields retain their current values when cloned:

<!DOCTYPE html>
<html>
<head>
  <title>Clone Form with Values</title>
</head>
<body>

  <form id="userForm">
    <input type="text" name="username" value="Samantha" /><br>
    <input type="checkbox" name="subscribe" checked /> Subscribe<br>
  </form>

  <button id="cloneFormBtn">Clone Form</button>

  <script>

    const form = document.getElementById('userForm');
    const button = document.getElementById('cloneFormBtn');

    button.addEventListener('click', () => {

      const clone = form.cloneNode(true);

      clone.style.border = '2px solid orange';
      clone.style.marginTop = '15px';

      document.body.appendChild(clone);

    });

  </script>

</body>
</html>

Try changing the username or toggling the checkbox before clicking the Clone Form button — you’ll see that the new form includes exactly what the user entered. There’s no need to manually copy value or checked states because cloneNode(true) already includes them.

This makes cloneNode(true) especially useful for duplicating forms dynamically — it captures both the structure and the user’s input, just as it appears on the page.

Cloning Form Elements with Manual Value Copying

Although modern browsers preserve form values when cloning nodes, it’s helpful to know how to copy values manually — especially when working with custom components or when you want full control.

In this example, we’ll create a clone of a form and manually copy the values from the original inputs into the cloned ones:

<!DOCTYPE html>
<html>
<head>
  <title>Manual Clone with Values</title>
</head>
<body>

  <form id="creatureForm">
    <input type="text" name="creature" value="Dragon" /><br>
    <input type="checkbox" name="isFlying" checked /> Can fly<br>
  </form>

  <button id="manualCloneBtn">Clone with Manual Values</button>

  <script>

    const form = document.getElementById('creatureForm');
    const button = document.getElementById('manualCloneBtn');

    button.addEventListener('click', () => {

      const clone = form.cloneNode(true);

      // Manually copy input values
      const originalInputs = form.querySelectorAll('input');
      const clonedInputs = clone.querySelectorAll('input');

      for (let i = 0; i < originalInputs.length; i++) {

        const original = originalInputs[i];
        const cloned = clonedInputs[i];

        if (original.type === 'checkbox' || original.type === 'radio') {
          cloned.checked = original.checked;
        } else {
          cloned.value = original.value;
        }

      }

      clone.style.border = '2px dashed green';
      clone.style.marginTop = '20px';

      document.body.appendChild(clone);

    });

  </script>

</body>
</html>

In this example, after cloning the form, the script loops through each original <input> and matches it with the corresponding cloned one. It then explicitly copies the value and checked state depending on the input type. This ensures everything stays in sync, even if you’re targeting environments or components where cloning doesn’t preserve state automatically or you just want to update the values some way.

Cloning with Event Listeners

Cloning nodes does not duplicate event listeners attached via JavaScript. This means if an element has a click event listener, the clone will not respond unless you add the listener again.

Here is a demonstration:

<!DOCTYPE html>
<html>
<head>
  <title>Event Listener Clone</title>
</head>
<body>

  <button id="originalBtn">Click Me!</button>
  <button id="cloneBtn">Clone the Button</button>

  <script>

    const originalBtn = document.getElementById('originalBtn');
    const cloneBtn = document.getElementById('cloneBtn');

    originalBtn.addEventListener('click', () => alert('Original button clicked!'));

    cloneBtn.addEventListener('click', () => {

      const clone = originalBtn.cloneNode(true);
      clone.textContent = 'I am the clone';
      document.body.appendChild(clone);

    });

  </script>

</body>
</html>

When you click the “Clone the Button” button, it creates a copy of the original button. The clone looks the same but does not show an alert when clicked because the event listener was not cloned.

Practical Fun Example: Cloning Cards in a Gallery

To tie it all together, here is an interactive example where clicking a “Clone Card” button duplicates a card containing an image and description.

<!DOCTYPE html>
<html>
<head>

  <title>Clone Gallery Card</title>

  <style>

    .card {
      border: 1px solid #444;
      padding: 10px;
      margin: 10px;
      width: 200px;
      display: inline-block;
      vertical-align: top;
      text-align: center;
    }

    .card img {
      width: 100%;
      height: auto;
    }

  </style>

</head>
<body>

  <div id="gallery">

    <div class="card">
      <img src="cat.jpg" alt="Kitten" />
      <p>Sleepy kitten</p>
      <button class="cloneBtn">Clone Card</button>
    </div>

  </div>

  <script>

    document.getElementById('gallery').addEventListener('click', e => {

      if (e.target.classList.contains('cloneBtn')) {

        const card = e.target.closest('.card');
        const clone = card.cloneNode(true);

        // Change button text on clone to avoid confusion
        clone.querySelector('.cloneBtn').textContent = 'Cloned!';

        // Append clone to gallery
        document.getElementById('gallery').appendChild(clone);

      }

    });

  </script>

</body>
</html>

This example clones an entire card with its image and button. The cloned card’s button text changes to “Cloned!” to show it’s a duplicate. This interactive gallery demonstrates how cloning can quickly create repeated content with all nested elements.

Conclusion

In this article, you explored how to clone elements in the DOM using JavaScript’s cloneNode() method. You learned the difference between shallow and deep cloning and saw how to add clones dynamically to your pages. You discovered how cloning interacts with form inputs and their values, and how event listeners are not cloned automatically. Finally, a fun gallery card cloning example showcased how cloning can power interactive, dynamic content with ease.

References

If you’re curious to explore further or want to double-check what you’ve learned, these trusted documentation pages offer more detailed explanations and examples:

Scroll to Top