Adding & Removing Elements

jQuery · Lesson 9 of 24 6 min read Updated

Real pages grow and shrink: a new message arrives, an item is added to a cart, a notification is dismissed. In this lesson you will create elements safely, insert them in the right place, move and copy them, and remove them, first with jQuery and then with the plain DOM methods that now do the same job with almost identical names.

You should be comfortable with .text() and the XSS warning from Text, HTML & Values, because the same safety rule applies here.

Creating elements

Pass an HTML tag to $() to create a new element. The safest pattern is an empty tag followed by .text(), or a tag plus an object of properties:

JavaScript
const $li = $("<li>").text("Diya set: ₹249");              // empty tag, then safe text
const $link = $("<a>", {                                     // tag plus properties
  href: "/offers",
  text: "See all offers",
  class: "offer-link",
});

// Plain JavaScript
const li = document.createElement("li");
li.textContent = "Diya set: ₹249";
const link = Object.assign(document.createElement("a"), { href: "/offers", textContent: "See all offers", className: "offer-link" });

A created element exists only in memory. Nothing appears until you insert it somewhere.

Inserting: inside or outside

jQuery has four basic insert methods, and the DOM now has the same four with similar names:

WherejQueryPlain JavaScript
Inside, at the end$parent.append(x)parent.append(x)
Inside, at the start$parent.prepend(x)parent.prepend(x)
Outside, just after$el.after(x)el.after(x)
Outside, just before$el.before(x)el.before(x)
Swap for a new one$el.replaceWith(x)el.replaceWith(x)

jQuery also has "reversed" versions where the new content comes first: .appendTo(), .prependTo(), .insertAfter() and .insertBefore(). They are handy in chains because they return the new element:

JavaScript
$("<li>").text("Rangoli colours").addClass("new").appendTo("#list");

There is one important difference between the two styles. With jQuery, .append("<b>Hi</b>") treats a string as HTML. With the DOM, append("<b>Hi</b>") treats a string as text, which is safer.

Run this festival shopping list. It creates items, adds them at the end or the start, and removes them:

HTMLTry it yourself
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Diwali shopping list</title>
  <style>
    li { margin: 0.2rem 0; }
    li.urgent { color: #b3261e; font-weight: bold; }
    li button { margin-inline-start: 0.5rem; }
  </style>
</head>
<body>
  <h2>Priya's Diwali list</h2>
  <input id="item" placeholder="Item" value="Sweets box">
  <label><input type="checkbox" id="urgent"> Urgent</label>
  <button id="add">Add</button>
  <ul id="list"></ul>
  <button id="clear">Clear list (plain JS)</button>

  <script src="https://cdn.jsdelivr.net/npm/jquery@4.0.0/dist/jquery.min.js"></script>
  <script>
    $("#add").on("click", function () {
      const name = $("#item").val().trim();
      if (!name) return;

      const $li = $("<li>").text(name);
      const $remove = $("<button>", { type: "button", text: "Remove" });
      $remove.on("click", function () {
        $(this).closest("li").remove();
      });
      $li.append($remove);

      if ($("#urgent").prop("checked")) {
        $li.addClass("urgent").prependTo("#list");   // urgent items go first
      } else {
        $("#list").append($li);
      }
      $("#item").val("").trigger("focus");
    });

    document.querySelector("#clear").addEventListener("click", () => {
      document.querySelector("#list").replaceChildren();   // remove every child
    });
  </script>
</body>
</html>

Removing: remove(), detach() and empty()

jQueryWhat it doesPlain JavaScript
.remove()Takes elements off the page and deletes their jQuery data and eventsel.remove()
.detach()Takes elements off the page but keeps their jQuery data and events, so you can put them backel.remove() (the variable still holds the element)
.empty()Removes all children, keeps the elementel.replaceChildren()

.detach() exists because jQuery stores event handlers and .data() values in its own internal storage. .remove() cleans that storage to avoid memory leaks, so a removed element that you re-insert has lost its jQuery handlers. Plain addEventListener handlers live on the element itself, so with plain DOM code, re-inserting a removed element keeps them.

HTMLTry it yourself
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>remove vs detach</title>
  <style>.chip { display: inline-block; padding: 0.3rem 0.7rem; margin: 0.3rem; border-radius: 1rem; background: #dff0ff; cursor: pointer; }</style>
</head>
<body>
  <p>Click a chip to count clicks. Then take both away and put them back.</p>
  <div id="area">
    <span class="chip" id="a">detached chip</span>
    <span class="chip" id="b">removed chip</span>
  </div>
  <button id="out">Take away</button>
  <button id="back">Put back</button>
  <p id="log"></p>

  <script src="https://cdn.jsdelivr.net/npm/jquery@4.0.0/dist/jquery.min.js"></script>
  <script>
    let clicks = 0;
    $(".chip").on("click", function () {
      clicks++;
      $("#log").text($(this).text() + " clicked. Total clicks: " + clicks);
    });

    let $a, $b;
    $("#out").on("click", function () {
      $a = $("#a").detach();   // events kept
      $b = $("#b").remove();   // events deleted
      $("#log").text("Both chips are off the page.");
    });
    $("#back").on("click", function () {
      if (!$a) return;
      $("#area").append($a, $b);
      $("#log").text("Back again. Click each chip: only the detached one still counts.");
    });
  </script>
</body>
</html>

Copying with clone()

.clone() copies elements. .clone(true) also copies jQuery event handlers and data. The DOM's cloneNode(true) copies the element and all its children, but never copies listeners added with addEventListener.

JavaScript
const $copy = $("#template-row").clone(true).removeAttr("id");
$("#table").append($copy);

// Plain JavaScript: clone the structure, then attach listeners again
const copy = document.querySelector("#template-row").cloneNode(true);
copy.removeAttribute("id");
document.querySelector("#table").append(copy);

For repeated pieces of markup, modern pages often use a <template> element and clone its content instead.

Inserting many elements quickly

Each insertion can make the browser recalculate the layout. Build everything first, then insert once:

JavaScript
const students = ["Aarav", "Meera", "Kabir", "Isha"];

// jQuery: an array of jQuery objects can be appended in one call
$("#class-list").append(students.map((name) => $("<li>").text(name)));

// Plain JavaScript: spread the elements into one append() call
const items = students.map((name) => Object.assign(document.createElement("li"), { textContent: name }));
document.querySelector("#class-list").append(...items);

Common mistakes

  • Building HTML strings with user input. Use $("<tag>").text(value) or textContent.
  • Appending one element to many targets and expecting one copy. $(".box").append($el) clones $el for every box except the last one, which gets the original.
  • Using .remove() when you plan to re-insert with jQuery events. Use .detach().
  • Inserting inside a loop. Collect the elements, then insert once.

Key points

  • Create elements with $("<li>") or document.createElement("li") and fill them with text, not HTML strings.
  • append, prepend, before, after and replaceWith exist in both jQuery and the DOM; jQuery strings are HTML, DOM strings are text.
  • .remove() deletes jQuery events and data; .detach() keeps them; .empty() clears children.
  • .clone(true) copies jQuery handlers; cloneNode(true) never copies listeners.
  • Build many elements first and insert them in one call.

Exercise

Create a "Notice board" with an input, an "Add notice" button and an empty <ul id="notices">. New notices should appear at the top of the list. Each notice gets a "Dismiss" button that removes it. Use jQuery for adding, and write the dismiss logic with plain JavaScript's closest() and remove() inside the jQuery-created button's handler.

Show solution
HTML
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Notice board</title>
</head>
<body>
  <input id="text" placeholder="Notice" value="Sports day on Friday">
  <button id="add">Add notice</button>
  <ul id="notices"></ul>
  <script src="https://cdn.jsdelivr.net/npm/jquery@4.0.0/dist/jquery.min.js"></script>
  <script>
    $("#add").on("click", function () {
      const text = $("#text").val().trim();
      if (!text) return;
      const $dismiss = $("<button>", { type: "button", text: "Dismiss" });
      $dismiss.on("click", function (event) {
        event.currentTarget.closest("li").remove();
      });
      $("<li>").text(text + " ").append($dismiss).prependTo("#notices");
      $("#text").val("");
    });
  </script>
</body>
</html>

.prependTo("#notices") puts each new notice first, and inside the handler event.currentTarget is the plain button element, so the DOM's closest() and remove() work on it directly.

Quick Quiz

1. Which jQuery call adds $li as the last child of #list?

2. What is the difference between .remove() and .detach()?

3. In plain JavaScript, what does list.append("<b>Hi</b>") show?

4. Does cloneNode(true) copy event listeners added with addEventListener?

Learn jQuery with a mentor

Free lessons get you started. Our Full Stack Web Development training adds real projects and code reviews from working developers.

  • Project-based learning
  • Mentor code reviews
  • Free counselling call