Nested Tabs with Vanilla JS (Top tabs and nested side tabs)

PHOTO EMBED

Fri Feb 11 2022 14:45:10 GMT+0000 (UTC)

Saved by @sarah__codes #javascript #html #css

<!-- CSS -->
   <style>
      .tabbed-content {
        position: relative;
        margin: 0 auto;
        overflow: hidden;
        width: 95%;
        margin: 0 auto;
        margin-left: 20px;
      }

      .tabs-wrapper {
        display: none;
      }

      .tabs-wrapper.current {
        display: inherit;
      }

      .tabs {
        margin: 0;
        padding: 0;
        margin-right: 30px;
        list-style: none;
        display: flex;
        line-height: normal;
      }
      .side.tabs {
        width: 200px;
        float: left;
        display: block;
        margin-top: 0px;
        height: 700px;
        overflow-y: auto;
        overflow-x: hidden;
        background: #f2f2f2;
      }

      /* Individual tab */
      .tab-link {
        color: #fff;
        display: block;
        padding: 15px 25px;
        margin-bottom: 0px;
        background: #c2c2c2;
        cursor: pointer;
        width: 150px;
        text-align: center;
        word-break: break-word;
        letter-spacing: 1.5px;
      }
      .side.tab-link {
        width: 225px;
        text-align: left;
        margin-top: 0px !important;
      }
      .tab-link:hover {
        background: #00693c;
      }
      .tab-link.current {
        background: #00693c;
        color: #fff;
      }
      .tab-content {
        display: none;
        border: 4px solid #cccccc;
        padding: 20px;
        margin: 0;
        float: left;
        min-height: 700px;
        width: 75%;
        box-sizing: border-box;
        position: relative;
      }
      .tab-content.current {
        display: inherit;
      }
    </style>


<!-- HTML FOR THE TABS -->
<div class="tabbed-content">
    <!-- Top Tab Navigation -->
    <ul class="tabs">
        <li class="top-nav tab-link current" data-tab="tides">TIDES</li>
        <li class="top-nav tab-link" data-tab="kentico">Kentico</li>
    </ul>

    <!-- Tabs Wrapper TIDES -->
    <div class="tabs-wrapper current" id="tides">
        <!-- Archive Video -->
        <div class="tab-content current" id="archive">
            <h3>How to Add to the TIDES Feature Archive</h3>
            <p>Small Description here</p>
            <div class="video-wrapper">
                <div class="video-container" id="video-container">
                    <video controls id="video" preload="metadata" width="600" height="400">
                        <source src="../video/2022/Kentico-Staging-Instructions.mp4" type="video/mp4" />
                    </video>
                </div>
            </div>
        </div>

        <!-- Marketing Email Calendar Video -->
        <div class="tab-content" id="calendar">
            <h3>How to Add to the Marketing Email Calendar</h3>
            <p>Small Description here</p>
            <p>Video Here</p>
        </div>

        <!-- TIDES SIDE TAB -->
        <ul class="side tabs">
            <li class="side tab-link current" data-tab="archive">
                How to Add to the TIDES Feature Archive
            </li>
            <li class="side tab-link" data-tab="calendar">
                How to Add to the Marketing Email Calendar
            </li>
        </ul>
    </div>

    <!-- Tabs Wrapper KENTICO -->
    <div class="tabs-wrapper" id="kentico">
        <!-- Kentico Staging Environment Video -->
        <div class="tab-content current" id="kenticoStaging">
            <h3>How to Use the Kentico Staging Environment</h3>
            <p>Small Description here</p>
            <p>Video Here</p>
        </div>

        <!-- Kentico SIDE TAB -->
        <ul class="side tabs">
            <li class="side tab-link current" data-tab="kenticoStaging">
                How to Use the Kentico Staging Environment
            </li>
        </ul>
    </div>
</div>
<!-- JAVASCRIPT FOR THE TABS -->
<script>
    const sideTabs = () => {
      let tabs = document.querySelectorAll(".side .tab-link");
    		let activeTopTab = document.getElementsByClassName("top-nav tab-link current")[0].getAttribute("data-tab");
    
    		tabs.forEach((btn) => {
    			btn.addEventListener("click", () => {
    				let closestTabWraper = btn.closest(".tabs-wrapper");
    		// only want to remove + add classes to sections that are currently visible or active 
    				if(closestTabWraper.id === activeTopTab) {
            //select only btns related to that top tab and remove the current class from all. Adding it back to only the one clicked. 
    					//this accounts for if a button is clicked on itself
    					let visibleTabs = closestTabWraper.querySelectorAll(".side .tab-link")
    					visibleTabs.forEach(b => b.classList.remove("current"));
    					btn.classList.add("current");
    					//Repeat the process for sections, but adding the class to the tabContent that matches the element id of the clicked tab
    					let relatedSections = closestTabWraper.querySelectorAll(".tab-content");
    					relatedSections.forEach(s =>s.classList.remove("current"));
    					let matchingTab = btn.getAttribute("data-tab");
                  document.getElementById(matchingTab).className += " current";
    				}
    			})
    		})
    };
    
    const topTabs = () => {
      const tabs = document.querySelectorAll(".top-nav");
      const tabWrappers = document.querySelectorAll(".tabs-wrapper");
    		tabs.forEach((btn) => {
    			btn.addEventListener("click", () => {
    				tabs.forEach(b => b.classList.remove("current"));
    				btn.classList.add("current");
    				tabWrappers.forEach(t => t.classList.remove("current"));
    				let matchingWrapper = btn.getAttribute("data-tab");
    				document.getElementById(matchingWrapper).classList.add("current");
    			});
    		})
    };
    
    topTabs();
    sideTabs();
</script>
content_copyCOPY

I was struggling with the "current" class being removed from sections that were currently hidden and you weren't able to double click on a button or the whole thing would break. The forEach solved this instead of using the convoluted for loops I was trying. ** Note that with the current CSS, this is not mobile responsive. Mainly saving this for the JS