For cloning a node, use the Node.cloneNode()
method. This allows you to clone a node and optionally all its child nodes as well.
This is effectively as if you copied its representing HTML, so only inline listeners, attributes etc. are copied.
Since the listeners are not copied, you would have to explicitely attach them to the clones 'again'.
Note: Make sure your DOM tree won't have duplicate IDs after cloning. Assign different IDs to the clones, or consider using a class instead.
By using event delegation, you could clone and add the elements without having to attach the listeners directly; they use the listener from their ancestor.
Here is an example of how this could look like:
const commonAncestor = document.getElementById("common-ancestor");
const topTablist = document.getElementById("top-tablist");
const bottomTablist = document.getElementById("bottom-tablist");
// Clone from top to bottom tablist; will use same listener from common ancestor
const clonedTablist = topTablist.cloneNode(true);
bottomTablist.replaceChildren(...clonedTablist.children);
// Event delegation: One listener on a common ancestor for multiple targets.
commonAncestor.addEventListener("click", evt => {
// Make sure a relevant element (here: `[role=tab]`) is the target.
const tab = evt.target.closest("[role=tab]");
if (tab === null) {
return;
}
selectPanel(tab.getAttribute("aria-controls"));
});
function selectPanel(panelId) {
const tabs = document.querySelectorAll("[role=tab]");
tabs.forEach(tab => {
const shouldSelect = tab.getAttribute("aria-controls") === panelId;
tab.ariaSelected = String(shouldSelect);
});
const panels = document.querySelectorAll("[role=tabpanel]");
panels.forEach(panel => {
const shouldHide = panel.id !== panelId;
panel.toggleAttribute("hidden", shouldHide);
});
}
#tabpanels {
border: 1px solid black;
width: 240px;
height: 160px;
display: grid;
}
<section id="common-ancestor">
<div id="top-tablist" role="tablist">
<button role="tab" aria-selected="true" aria-controls="panel-1">Tab 1</button>
<button role="tab" aria-selected="false" aria-controls="panel-2">Tab 2</button>
</div>
<div id="tabpanels">
<div id="panel-1" role="tabpanel">Panel 1</div>
<div id="panel-2" role="tabpanel" hidden>Panel 2</div>
</div>
<div id="bottom-tablist" role="tablist">
<!--Empty, will be filled via JS-->
</div>
</section>