A tabs component that provides different sections of content that are displayed one at a time when the user selects that information.
The tabbed user interface enables users to jump to their target section quickly. Tabs present like logically group information on the same page. Information should
Users should not need to see content of multiple tabs simultaneously and the user should be able to easily recognise where they are within the content.
The structure of the tab set is defined in html. There are two forms supported. Adding a class of .tab-group
to the container element will work in place of the tabset
tag, and the tab panels can be defined using either tab=""
or data-tab=""
. Passing an optional element to the init function will initialise tabs within that element.
tabset#uniqueID div(tab="[tab title]") div(tab="[tab title]")
tabset, .tab-group { margin: 2rem 0 1rem 0; } tabset > ul, .tab-group > ul { display: -webkit-box; display: -ms-flexbox; display: flex; margin: 0; padding: 0; } tabset > ul li.separator, .tab-group > ul li.separator { border-bottom: 1px solid #7f7f7f; border-left: 1px solid #7f7f7f; display: inline-block; margin: 0.45rem 0 0 0; width: 100%; } tabset .tab-hidden, .tab-group .tab-hidden { display: none; } tabset [role=tab], .tab-group [role=tab] { background-color: #FFF; border-left: 1px solid #7f7f7f; border-top: 1px solid #7f7f7f; border-radius: 0.5rem 0.5rem 0 0; cursor: pointer; margin: 0; display: inline; padding: 1rem 1.5rem 0.14rem 1.5rem; z-index: 2; } tabset [role=tab]:last-of-type, .tab-group [role=tab]:last-of-type { border-right: 1px solid #7f7f7f; } tabset [role=tab]:not(.selected), .tab-group [role=tab]:not(.selected) { background-color: #f0f0f0; border-bottom: 1px solid #7f7f7f; } tabset [role=tab] span, .tab-group [role=tab] span { display: block; margin: 0 0 0.5rem 0; } tabset [role=tabpanel], .tab-group [role=tabpanel] { background-color: #FFF; border: 1px solid #7f7f7f; border-top: none; padding: 1rem; z-index: 1; } tabset [role=tabpanel]:not(.open), .tab-group [role=tabpanel]:not(.open) { display: none; }
@import "scss/core/tabs/_tabs"; @include tabs{ // optional content block };
// DS2 core (c) 2024 Alexander McIlwraith // Licensed under CC BY-SA 4.0 $tab-border: #7f7f7f !default; $tab-selected: #FFF !default; $tab-notselected: #f0f0f0 !default; @mixin tabs { tabset, .tab-group { margin: 2rem 0 1rem 0; > ul { display: flex; margin: 0; padding: 0; li.separator { border-bottom: 1px solid $tab-border; border-left: 1px solid $tab-border; display: inline-block; margin: .45rem 0 0 0; width: 100%; } } .tab-hidden { display: none; } [role="tab"] { background-color: $tab-selected; border-left: 1px solid $tab-border; border-top: 1px solid $tab-border; border-radius: .5rem .5rem 0 0; cursor:pointer; margin: 0; display: inline; padding: 1rem 1.5rem .14rem 1.5rem; z-index: 2; &:last-of-type { border-right: 1px solid $tab-border; } &:not(.selected) { background-color: $tab-notselected; border-bottom: 1px solid $tab-border; } span { display: block; margin: 0 0 .5rem 0; } } [role="tabpanel"] { background-color: $tab-selected; border: 1px solid $tab-border; border-top: none; padding: 1rem; z-index: 1; &:not(.open) { display: none; } @content; } } }
import * as tabs from "./js/core/tabs/_tabs.js"; tabs.init();
/* DS2 core (c) 2024 Alexander McIlwraith Released under Creative Commons Attribution-ShareAlike 4.0 International */ // create a pure JS mouse click event const click = new MouseEvent('click', { view: window, bubbles: false, cancelable: true }); export function init(p = document, s = true) { p.querySelectorAll(".tab-group, tabset").forEach(tabGroup => { if (tabGroup.querySelector("[role=tablist]") === null) { const tabgroup = tabGroup.getAttribute("id"); let tablist = ""; Array.from(tabGroup.children).forEach(child => { const tab = child.getAttribute("tab") || child.getAttribute("data-tab"); if (tab !== null) { const tabID = tab.replace(/\W+/g, "-").toLowerCase(); const tabPanel = document.createElement('div'); tabPanel.id = `tab-panel-${tabgroup}-${tabID}`; tabPanel.className = tablist === "" ? "open" : ""; tabPanel.setAttribute("role", "tabpanel"); tabPanel.setAttribute("tabindex", "0"); tabPanel.setAttribute("aria-labelledby", `tab-${tabgroup}-${tabID}`); tabPanel.appendChild(child.cloneNode(true)); child.parentNode.replaceChild(tabPanel, child); tablist += `