The .clone() method creates a deep copy of matched elements (and their descendants). This tutorial covers basic cloning, cloning with event handlers and data, deep cloning of children’s events, modifying clones before insert, comparisons with move-vs-copy insertion, duplicate id pitfalls, five practical examples, and try-it labs.
01
.clone()
Deep copy
02
Events
.clone(true)
03
Deep
Children too
04
Modify
Then insert
05
vs move
appendTo
06
Since 1.0
Core API
Fundamentals
Introduction
Apps often need a second copy of a card, list item, or form row — keep the template on the page and duplicate it when the user clicks “Add another.” jQuery’s .clone() builds that copy for you.
Available since jQuery 1.0, .clone() performs a deep copy: the matched elements plus all descendant elements and text nodes. By default, event handlers are not copied. Pass true to include handlers and (since 1.4) element data. Since 1.5, a second Boolean controls whether children also get events and data.
Cloning alone does not insert anything. Chain .appendTo(), .prependTo(), or .insertAfter() to place the copy. Without .clone(), those same methods move existing nodes. Browse the jQuery DOM hub for related methods.
Concept
Understanding the .clone() Method
.clone( [withDataAndEvents] [, deepWithDataAndEvents] ) returns a new jQuery collection containing copies of the matched set. The originals stay where they are. Descendants are always included in the structure copy.
The first Boolean (default false) copies event handlers and, since 1.4, data attached with .data(). The second Boolean (since 1.5) defaults to the same value as the first and applies that choice to all children.
💡
Beginner Tip
Think: $(".hello").appendTo(".goodbye")moves the hello block. $(".hello").clone().appendTo(".goodbye")copies it so both places show Hello — the classic official jQuery demo pattern.
⚠️
Duplicate IDs
Cloning copies the id attribute. HTML requires unique IDs. After .clone(), update the clone’s id (and related for / ARIA refs) before inserting, or avoid IDs on template elements you plan to duplicate.
Foundation
📝 Syntax
jQuery .clone() supports two signatures:
Clone structure only — since 1.0
jQuery
.clone( [withDataAndEvents] )
withDataAndEvents (default false) — copy event handlers; since 1.4 also copy .data().
Original <b> remains in place
A copy is prepended inside each <p>
Deep copy includes text inside <b>
How It Works
.clone() builds detached copies. .prependTo("p") inserts each copy as the first child of every matched paragraph. Event handlers are not copied unless you pass true.
Example 2 — Clone vs Move With .appendTo()
Without .clone(), inserting an existing node moves it. With .clone(), both copies remain.
jQuery
// Moves .hello into .goodbye (original location empty)
$( ".hello" ).appendTo( ".goodbye" );
// Keeps original .hello and adds a copy inside .goodbye
$( ".hello" ).clone().appendTo( ".goodbye" );
Move: Hello appears only under Goodbye
Clone: Hello appears in both places
Always clone when you need a duplicate, not a relocate
How It Works
Insertion methods operate on the matched set. If those elements are already in the document, jQuery relocates them. Cloning first creates new nodes so insertion does not empty the original parent.
📈 Practical Patterns
Events, template editing, and deep cloning for nested widgets.
Example 3 — Clone With Event Handlers
Pass true so click handlers on the original also work on the copy.
New .row appears with the same click handlers
Input value cleared on the clone only
.clone(true) copies handlers + .data() on the matched element
How It Works
.clone(true) duplicates handlers bound with jQuery. Nested interactive children may still need .clone(true, true). Objects/arrays stored in .data() are shared by reference unless you deep-copy them manually with $.extend.
Example 4 — Modify the Clone Before Inserting
Change text, remove the template id, then append the prepared copy.
Template keeps id="card-template"
Clone has no id, updated heading, appended to #board
Safe pattern for reusable UI templates
How It Works
The jQuery docs note you can modify clones before re-inserting. Use .find().end() to edit descendants then return to the root clone for .appendTo(). Always strip or rewrite IDs on templates.
Example 5 — Deep Clone Events on Children
Use two true arguments so nested buttons keep their handlers.
Widget structure duplicated
Nested button click still fires on the copy
New id avoids duplicate #widget
How It Works
.clone(true) alone copies events on the matched root. Nested elements that were bound separately need .clone(true, true) (jQuery 1.5+). Prefer event delegation (.on("click", ".child", fn) on a parent) when many clones share the same behavior — then a plain .clone() is enough.
Applications
🚀 Common Use Cases
Dynamic form rows — clone a field group when the user adds another item.
Card / widget templates — keep a hidden template and clone it into a board.
List duplication — copy a selected item instead of rebuilding HTML strings.
Demo / preview panes — show a read-only clone of a live component.
Preserving interactivity — .clone(true) or .clone(true, true) for widgets with handlers.
Safer than string HTML — clone existing trusted markup instead of concatenating HTML from data.
🧠 How .clone() Builds a Copy
1
Match source elements
Select the nodes you want to duplicate (and their descendants).
Select
2
Deep-copy the tree
Structure and text nodes are copied; optionally events and data too.
Clone
3
Optionally edit the copy
Change ids, text, classes, or clear inputs before insertion.
Modify
4
📋
Insert into the document
Chain .appendTo(), .prependTo(), .after(), or similar.
Important
📝 Notes
Available since jQuery 1.0; second parameter since 1.5; data copied with events since 1.4.
Always a deep structural copy of descendants — there is no “shallow element only” mode.
Default does not copy event handlers; use .clone(true) or .clone(true, true).
Objects and arrays in .data() are shared between original and clone unless you deep-copy them.
Duplicated id attributes are invalid HTML — rewrite or remove them on clones.
textarea typed values and select selections are not copied for performance; input dynamic state generally is.
Event delegation on a stable parent often beats deep-cloning handlers for repeating UI.
Compatibility
Browser Support
.clone() has been part of jQuery since 1.0+. The withDataAndEvents option dates to 1.0 (with data included since 1.4); deepWithDataAndEvents was added in 1.5+. Works in all browsers supported by your jQuery build — including modern evergreen browsers with jQuery 3.x and 4.x.
✓ jQuery 1.0+
jQuery .clone()
Universal deep-copy API across jQuery 1.x–4.x. No browser-specific polyfills — jQuery normalizes cloning and optional event/data copying.
100%With jQuery loaded
Google ChromeAll versions · Desktop & Mobile
Full support
Mozilla FirefoxAll versions · Desktop & Mobile
Full support
Apple SafariAll versions · macOS & iOS
Full support
Microsoft EdgeAll versions · Chromium & Legacy
Full support
Internet ExplorerIE 6+ · Legacy environments
Full support
OperaAll modern versions
Full support
.clone()Universal
Bottom line: Default choice for duplicating DOM subtrees before insertion.
Wrap Up
Conclusion
The jQuery .clone() method deep-copies matched elements and their descendants. Chain an insertion method to place the copy, pass true (and optionally a second true) when events and data must travel with the duplicate, and always fix unique attributes like id before inserting.
Prefer event delegation when many identical clones share behavior. Next up: inserting matched elements after a target with .insertAfter().
Use .clone() when you need a duplicate, not a move
Remove or rename id on clones before inserting
Use .clone(true) / .clone(true, true) when handlers must copy
Edit the clone (text, values, classes) before .appendTo()
Prefer delegated events on a parent for repeating rows
❌ Don’t
Expect .appendTo() alone to copy — it moves existing nodes
Leave duplicate IDs in the document after cloning
Assume textarea / select user state is copied
Share mutable .data() arrays/objects without deep-copying
Deep-clone events when simple event delegation would suffice
Summary
Key Takeaways
Knowledge Unlocked
Five things to remember about .clone()
The duplicate-then-insert API for DOM subtrees.
5
Core concepts
📋01
Deep
Copy
Structure
≠02
Not
A move
vs appendTo
⚡03
Events
Optional
.clone(true)
#04
Fix
IDs
Unique
→05
Then
Insert
Chain
❓ Frequently Asked Questions
.clone() creates a deep copy of the matched elements, including all descendant elements and text nodes. The original stays in place. You usually chain an insertion method such as .appendTo() or .insertAfter() to put the copy into the document. Available since jQuery 1.0.
Appending (or .appendTo()) an element already in the document moves it to the new location. Calling .clone() first copies it, so the original remains and the copy is inserted. Use clone when you need duplicates.
By default, no. Pass true as the first argument — .clone(true) — to copy event handlers and (since 1.4) .data() values. As of 1.5, a second argument deepWithDataAndEvents controls whether children also get events and data copied.
The optional second Boolean (jQuery 1.5+) controls whether event handlers and data on all descendants of the cloned element are copied. By default it matches the first argument. Use .clone(true, true) to copy events/data on the element and its children.
Cloning copies attributes, including id. IDs must be unique in a document. After cloning, change the clone’s id (and any label[for] / aria references) before inserting, or prefer class-based selectors for elements you plan to duplicate.
For input elements, the dynamic state (typed text, checkbox selection) is generally retained on clones. For performance reasons, user data typed into textarea and selections on select are not copied to the clone — re-apply those values if needed.
Did you know?
.clone() has been in jQuery since version 1.0. The ability to copy events arrived early; copying .data() alongside events landed in 1.4, and deep child event/data copying arrived in 1.5. In 1.5.0 the default for withDataAndEvents briefly flipped to true before returning to false in 1.5.1 — always pass an explicit Boolean in production code for clarity.