<div class="main container">
<div class="widget">
<div class="widget-container">
<div class="tab-container">
<div class="tab-list" role="tablist">
<button role="tab" class="tab active" aria-controls="tab-content-01" id="tab-01" tabindex="0" aria-selected="true"><span>About</span></button>
<button role="tab" class="tab" aria-controls="tab-content-02" id="tab-02" tabindex="-1" aria-selected="false"><span>Services</span></button>
<button role="tab" class="tab" aria-controls="tab-content-03" id="tab-03" tabindex="-1" aria-selected="false"><span>Products</span></button>
<div class="follow"></div>
</div> <!-- tablist -->
<div class="tab-content-wrapper">
<div class="tab-content tab-active" id="tab-content-01" tabindex="0" role="tabpanel" aria-labelledby="tab-01">
<h2>About</h2>
<p>
<code class="snippet">Use your mouse or keyboard to switch tabs </code>
<ul>
<li>
Click tabs using mouse or;
</li>
<li>While focused on active tab, use <code>Left</code> and <code>Right</code> arrow keys </li>
</ul>
</p>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Corporis rerum repudiandae illum ipsam
voluptates
tempore eos? Voluptates illum laborum, porro, expedita sint nulla similique natus amet harum, voluptas
quae explicabo!</p>
<a href="#">This is a link </a>
</div>
<div class="tab-content" id="tab-content-02" hidden tabindex="0" role="tabpanel" aria-labelledby="tab-02">
<h2>Services</h2>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Corrupti fuga nostrum temporibus exercitationem
commodi molestias tenetur, iusto aut laboriosam error impedit debitis a vitae similique enim voluptatem
vero, officiis consectetur!
<a href="#">This is a link </a>
</div>
<div class="tab-content" id="tab-content-03" hidden tabindex="0" role="tabpanel" aria-labelledby="tab-03">
<h2>Products</h2>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Maxime officia iste illum, nostrum esse sit
eveniet laboriosam velit aspernatur fuga, illo quam nulla voluptatem nemo, earum pariatur quis beatae
magni!
<a href="#">This is a link </a>
</div>
</div>
<!--tab-content-wrapper -->
</div>
</div>
</div>
</div>
/**
include https://codepen.io/chrisbautista/pen/ZEryzKx.css
*/
// tabbed container
.tab-container {
$tabPadding: 0.7rem 8px;
$margin: 0 0.1rem 0.4rem 0;
h2 {
font-size: 1.6em;
font-weight: bold;
margin-top: 0.5em;
}
.tab-list {
position: relative;
padding: 2px 5px 0;
margin: 0;
display: flex;
justify-content: flex-start;
border-bottom: $hairlines;
width: 100%;
overflow: hidden;
&.navigation-selected {
button {
&:focus:not(:focus-visible) {
outline: 2px solid #5a5a5a;
}
}
}
.follow {
background-color: $colorHairlines;
border-top-left-radius: 1rem;
border-top-right-radius: 1rem;
display: inline-flex;
font-weight: bold;
height: 27px;
left: 0;
position: absolute;
top: 2px;
width: 55px;
z-index: 1;
box-shadow: shadow(low);
transition: left 0.25s ease-out, width 0.25s ease;
}
.tab {
position: relative;
z-index: 2;
display: inline-flex;
justify-content: center;
align-items: center;
background-color: transparent;
padding: 0;
margin: 0;
width: 100%;
height: 100%;
color: $colorTextPrimary;
border: 0;
box-shadow: none;
border-top-left-radius: 1rem;
border-top-right-radius: 1rem;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
font-size: 0.875rem;
padding: $tabPadding;
transition: color 0.25s ease-out 0.125s;
span {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
overflow: hidden;
width: 100%;
text-align: center;
vertical-align: center;
}
&.is-keyboard-selected {
&:focus:not(:focus-visible) {
outline: 2px solid #5a5a5a;
}
}
&:focus:not(:focus-visible) {
outline: none;
}
&.active {
color: $colorUiOk;
}
&:last-child {
margin-right: 0;
}
}
}
.tab-content-wrapper {
position: relative;
display: flex;
}
.tab-content {
display: none;
background-color: $colorCanvas;
margin-top: 0.2rem;
&.tab-active {
display: block;
}
&:focus:not(:focus-visible) {
outline: none;
}
&.is-keyboard-selected {
&:focus:not(:focus-visible) {
outline: 2px solid #5a5a5a;
}
}
}
}
// presentation
.main {
margin: 0 auto;
padding: min(5%, 2.5rem) 0;
justify-content: center;
width: min(90%, 600px);
}
View Compiled
const q = (selector, elem = document) => elem.querySelector(selector);
const qAll = (selector, elem = document) => elem.querySelectorAll(selector);
const rect = (elem) => elem.getBoundingClientRect();
(function setupTabContainers() {
const tabContainers = qAll(".tab-container");
tabContainers.forEach(setup);
function setup(tabContainer) {
const tabs = qAll(".tab", tabContainer);
const follow = q(".tab-list .follow", tabContainer);
let currentTabIndex = 0;
let currentTab = tabs[currentTabIndex];
let currentTabPanel = q(".tab-content.tab-active", tabContainer);
if (!currentTabPanel) {
currentTabPanel = q("tab-content", tabContainer)[currentTabIndex];
}
setActiveTab();
function onTabSelect(e) {
updateTabs(e.currentTarget);
}
function onTabContainerKeyUp(e) {
e.preventDefault();
e.stopPropagation();
if (tabs[currentTabIndex] != document.activeElement) {
return;
}
if (e.code === "ArrowRight" || e.key === "ArrowRight") {
nextTab();
} else if (e.code === "ArrowLeft" || e.key === "ArrowLeft") {
prevTab();
}
}
function nextTab() {
currentTabIndex++;
if (currentTabIndex >= tabs.length) {
currentTabIndex = tabs.length - 1;
}
const currentTab = tabs[currentTabIndex];
updateTabs(currentTab, true);
currentTab.focus();
}
function prevTab() {
currentTabIndex--;
if (currentTabIndex < 0) {
currentTabIndex = 0;
}
const currentTab = tabs[currentTabIndex];
updateTabs(currentTab, true);
currentTab.focus();
}
function updateTabs(target, isKeyboard = false) {
currentTab.classList.remove("is-keyboard-selected");
currentTab.classList.toggle("active");
currentTab.setAttribute("aria-selected", false);
currentTab.setAttribute("tabindex", "-1");
target.classList.toggle("active");
currentTab = target;
setActiveTab(isKeyboard);
setContent(currentTab.getAttribute("aria-controls"), isKeyboard);
}
function getActiveTabProps(tabRect) {
const parentRect = tabContainer.getBoundingClientRect();
return {
left: tabRect.left - parentRect.left,
width: tabRect.width,
height: tabRect.height
};
}
function setActiveTab(isKeyboard) {
const tabRect = rect(currentTab);
const newProps = getActiveTabProps(tabRect);
follow.style.left = `${newProps.left}px`;
follow.style.width = `${newProps.width}px`;
follow.style.height = `${newProps.height}px`;
currentTab.setAttribute("aria-selected", true);
currentTab.setAttribute("tabindex", "0");
if (isKeyboard) {
currentTab.classList.add("is-keyboard-selected");
}
}
function setContent(selector, isKeyboard) {
// old tab content
currentTabPanel.classList.toggle("tab-active");
if (isKeyboard) {
currentTabPanel.blur();
currentTabPanel.classList.remove("is-keyboard-selected");
}
currentTabPanel.setAttribute("tabindex", "-1");
currentTabPanel.setAttribute("hidden", true);
// new tab content
currentTabPanel = q(`#${selector}`, tabContainer);
currentTabPanel.classList.toggle("tab-active");
currentTabPanel.removeAttribute("hidden");
currentTabPanel.setAttribute("tabindex", "0");
if (isKeyboard) {
currentTabPanel.classList.add("is-keyboard-selected");
currentTabPanel.focus();
}
}
function onResize() {
setActiveTab();
}
tabs.forEach((tab) => {
tab.addEventListener("click", onTabSelect);
});
tabContainer.addEventListener("keyup", onTabContainerKeyUp);
window.addEventListener("resize", onResize);
}
})();
View Compiled
This Pen doesn't use any external JavaScript resources.