Inspect the fixed example
Register one listener, deep-clone the button and give the copy a unique ID. The script clicks original and copy once each.
<style>html{font-size:16px}body{margin:12px;font:1rem/1.5 system-ui,sans-serif;color:#17332d;background:#fff}p{overflow-wrap:anywhere}output{display:block;margin-block:12px;overflow-wrap:anywhere;white-space:pre-wrap}button,input{font:inherit;max-width:100%;box-sizing:border-box}button{margin:4px;padding:8px}label{display:block;margin-block:8px}button:focus-visible,input:focus-visible{outline:3px solid #23715d;outline-offset:2px}ul{padding-inline-start:24px}li{overflow-wrap:anywhere}.highlight{border:2px solid green}</style>
<button id="original" type="button"><span>Original</span></button><output id="result"></output>
<script>let count=0;const original=document.querySelector('#original');original.addEventListener('click',()=>count++);const copy=original.cloneNode(true);copy.id='copy';copy.querySelector('span').textContent='Copy';original.after(copy);original.click();copy.click();
const result=count;
document.querySelector('#result').textContent=JSON.stringify(result);
console.log(JSON.stringify(result));
</script>1| Inspection | Supplied input or action | Result |
|---|---|---|
| Original click | #original | count: 1 |
| Copy click | #copy | count: 1 |
| IDs | original / copy | Distinct IDs |
Follow the native mechanism
cloneNode(true) copies the node’s attributes and descendants. Listeners registered with addEventListener are not copied. Unique IDs require an explicit change; deep cloning does not provide it. This fixture has no inline event-handler attributes, whose copying would be a different boundary.
Compare the material alternative
Leaving the copied ID unchanged creates two matching IDs while the copy still has no registered handler. Appearance and deep=true do not establish behavior.
<style>html{font-size:16px}body{margin:12px;font:1rem/1.5 system-ui,sans-serif;color:#17332d;background:#fff}p{overflow-wrap:anywhere}output{display:block;margin-block:12px;overflow-wrap:anywhere;white-space:pre-wrap}button,input{font:inherit;max-width:100%;box-sizing:border-box}button{margin:4px;padding:8px}label{display:block;margin-block:8px}button:focus-visible,input:focus-visible{outline:3px solid #23715d;outline-offset:2px}ul{padding-inline-start:24px}li{overflow-wrap:anywhere}.highlight{border:2px solid green}</style>
<button id="original" type="button"><span>Original</span></button><output id="result"></output>
<script>let count=0;const original=document.querySelector('#original');original.addEventListener('click',()=>count++);const copy=original.cloneNode(true);original.after(copy);copy.click();
const result={duplicateIds:document.querySelectorAll('#original').length,count};
document.querySelector('#result').textContent=JSON.stringify(result);
console.log(JSON.stringify(result));
</script>{"duplicateIds":2,"count":0}Work the boundary
What must be done to give the new copy an independent click handler?
Show the worked answer
Assign its unique ID and explicitly register its handler. The repaired fixed run increments each independent counter once.
<style>html{font-size:16px}body{margin:12px;font:1rem/1.5 system-ui,sans-serif;color:#17332d;background:#fff}p{overflow-wrap:anywhere}output{display:block;margin-block:12px;overflow-wrap:anywhere;white-space:pre-wrap}button,input{font:inherit;max-width:100%;box-sizing:border-box}button{margin:4px;padding:8px}label{display:block;margin-block:8px}button:focus-visible,input:focus-visible{outline:3px solid #23715d;outline-offset:2px}ul{padding-inline-start:24px}li{overflow-wrap:anywhere}.highlight{border:2px solid green}</style>
<button id="original" type="button"><span>Original</span></button><output id="result"></output>
<script>let originalCount=0,copyCount=0;const original=document.querySelector('#original');original.addEventListener('click',()=>originalCount++);const copy=original.cloneNode(true);copy.id='copy';copy.addEventListener('click',()=>copyCount++);original.after(copy);original.click();copy.click();
const result={originalCount,copyCount,spanCopied:copy.querySelectorAll('span').length,uniqueIds:new Set([original.id,copy.id]).size};
document.querySelector('#result').textContent=JSON.stringify(result);
console.log(JSON.stringify(result));
</script>{"originalCount":1,"copyCount":1,"spanCopied":1,"uniqueIds":2}