Scalable Buttoned Tabs
Tabbed component with scalable properties! Simply add some more buttons and sections and the code will dynamically update to support the amount of tabs!
This is the 1st tabbed component!
This is the 2nd tabbed component!
This is the 3rd tabbed component!
<div class="tabbed-component"> <ul class="tabbed-component__list"> <li class="tabbed-component__item tabbed-component__item--active" data-section="1"> <button class="tabbed-component__button">Section 1</button> </li> <li class="tabbed-component__item" data-section="2"> <button class="tabbed-component__button">Section 2</button> </li> <li class="tabbed-component__item" data-section="3"> <button class="tabbed-component__button">Section 3</button> </li> </ul> <div class="tabbed-component__container"> <div class="tabbed-component__section tabbed-component__section--active" id="section-1"> <h2>This is the 1st tabbed component!</h2> </div> <div class="tabbed-component__section" id="section-2"> <h2>This is the 2nd tabbed component!</h2> </div> <div class="tabbed-component__section" id="section-3"> <h2>This is the 3rd tabbed component!</h2> </div> </div> </div>
// name of root element const rootComponentName = "tabbed-component"; // define object storing classnames const classes = { container: rootComponentName, buttonList: `${rootComponentName}__list`, buttonContainer: `${rootComponentName}__item`, buttonActive: `${rootComponentName}__item--active`, button: `${rootComponentName}__button`, sectionContainer: `${rootComponentName}__container`, section: `${rootComponentName}__section`, sectionActive: `${rootComponentName}__section--active` }; // propagate event listener to button container to prevent x seperate functions to each of the buttons document .querySelector(`.${classes.buttonList}`) .addEventListener("click", (e) => { // if the click event was on one of the buttons (not the container outside) const el = e.target.closest(`.${classes.buttonContainer}`); // return if something other than the button is clicked if (!el) return; // store data in data-section="" html attribute let id = el.dataset.section; // return if tabbed selection already has the section if ( document .getElementById(`section-${id}`) .classList.contains(classes.sectionActive) ) return; // query the DOM to find all buttons and remove active button let buttons = document.querySelectorAll(`.${classes.buttonContainer}`); removeClassFromNodeList(buttons, classes.buttonActive); // add the active class to the new button from event el.classList.toggle(classes.buttonActive); // store all sections in a node list let sections = document.querySelectorAll(`.${classes.section}`); removeClassFromNodeList(sections, classes.sectionActive); // add active class to section from dataset of button clicked document .getElementById(`section-${id}`) .classList.add(classes.sectionActive); console.log(id); }); // function to accept a nodelist and class, and loop through the list to remove html class from all nodes const removeClassFromNodeList = (nodeList, className) => { nodeList.forEach((cur) => { cur.classList.remove(className); }); };
csslab
CSSLab is a platform dedicated to providing high-quality, scalable & reusable components that can be easily slotted into all kinds of web applications.
©2024 CSSLab, all rights reserved.