<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Nested JS Tabs</title>
<!-- Basic Styles for the Tabs -->
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
padding: 2rem;
background-color: #f4f7f6;
}
.tabs-container {
max-width: 600px;
margin: 0 auto 2rem auto; /* Add margin-bottom to separate tab groups */
background: #fff;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
/* Style for nested tabs */
.tab-content .tabs-container {
max-width: 100%;
margin-top: 1rem;
box-shadow: inset 0 2px 8px rgba(0,0,0,0.06);
border: 1px solid #e9ecef;
}
.tab-titles {
display: flex;
border-bottom: 1px solid #dee2e6;
background-color: #f8f9fa;
}
.tab-title {
padding: 1rem 1.5rem;
cursor: pointer;
border-bottom: 3px solid transparent;
margin-bottom: -1px; /* Aligns with the container's border */
transition: all 0.2s ease-in-out;
font-weight: 500;
color: #495057;
}
.tab-title.active {
color: #007bff;
border-bottom-color: #007bff;
background-color: #fff;
}
.tab-contents {
padding: 1.5rem;
}
.tab-content {
line-height: 1.6;
}
/* Utility class to hide elements */
.hidden {
display: none;
}
</style>
</head>
<body>
<!-- PARENT TAB GROUP -->
<!-- Note: The 'active' class is no longer needed in the HTML -->
<div class="tabs-container">
<!-- Tab Titles -->
<div class="tab-titles">
<div class="tab-title">Outer Tab 1</div>
<div class="tab-title">Outer Tab 2 (With Nested Tabs)</div>
</div>
<!-- Tab Contents -->
<div class="tab-contents">
<div class="tab-content">
<p><strong>Content for Outer Tab 1.</strong> This is the first level of tabs.</p>
</div>
<div class="tab-content hidden">
<p>This is the content for Outer Tab 2.</p>
<!-- NESTED TAB GROUP -->
<div class="tabs-container">
<div class="tab-titles">
<div class="tab-title">Inner Tab A</div>
<div class="tab-title">Inner Tab B</div>
</div>
<div class="tab-contents">
<div class="tab-content">
<p><strong>Content for Inner Tab A.</strong> This tab group is completely independent and nested.</p>
</div>
<div class="tab-content hidden">
<p><strong>Content for Inner Tab B.</strong> Clicking these tabs does not affect the outer tabs.</p>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
/**
* Initializes a single tab group based on its container.
* It finds all titles and contents that are DIRECT children and wires them up.
* @param {HTMLElement} tabContainer - The .tabs-container element.
*/
function initializeTabs(tabContainer) {
// Find title and content elements using more specific selectors.
// ':scope' refers to the 'tabContainer' element itself.
// This ensures we only get the direct children of the container's
// '.tab-titles' and '.tab-contents' wrappers, ignoring any nested tabs.
const titles = tabContainer.querySelectorAll(':scope > .tab-titles > .tab-title');
const contents = tabContainer.querySelectorAll(':scope > .tab-contents > .tab-content');
if (titles.length !== contents.length) {
console.error("Mismatch between tab titles and content panels.", tabContainer);
return;
}
/**
* Switches the visible tab to the one at the specified index.
* @param {number} activeIndex - The index of the tab to show.
*/
function switchTab(activeIndex) {
titles.forEach((title, index) => {
title.classList.toggle('active', index === activeIndex);
});
contents.forEach((content, index) => {
content.classList.toggle('hidden', index !== activeIndex);
});
}
// Add a click event listener to each tab title
titles.forEach((title, index) => {
title.addEventListener('click', () => {
switchTab(index);
});
});
// --- INITIALIZE ---
// Programmatically set the first tab (index 0) as active on load.
switchTab(0);
}
// --- Main Execution ---
// Find all tab containers on the page and initialize each one independently.
// The script will run on the outer container first, then on the inner one.
const allTabContainers = document.querySelectorAll('.tabs-container');
allTabContainers.forEach(initializeTabs);
});
</script>
</body>
</html>
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.