<div class="tab " role="tablist">
<button class="tab__title tab__title--active " data-tab="tab-1" id="tab-title-1" aria-controls="tab-1" aria-selected="true" aria-expanded="true" role="tab">
Tab title
<svg class="icon tab__icon" role="presentation" focusable="false">
<use href="/images/icons-sprite.svg#angle-down"></use>
</svg>
</button>
<div class="
tab__content
tab__content--active
" id="tab-1" data-content="tab-1" aria-labelledby="tab-title-1" aria-hidden="false" role="tabpanel">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque pharetra ut magna ornare lacinia. Cras sodales elit ac pellentesque aliquet. Nulla nec viverra turpis. Mauris eget quam interdum, viverra enim eget, ultricies purus. Suspendisse eleifend, turpis id pretium consectetur, massa nunc suscipit elit, a porta neque neque sed ex. Curabitur nec ante non urna rhoncus semper. Maecenas id pulvinar erat. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque mollis sit amet quam id vestibulum. Nunc faucibus quam non venenatis laoreet. Pellentesque eu feugiat tellus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.</p>
</div>
<button class="tab__title " data-tab="tab-2" id="tab-title-2" aria-controls="tab-2" aria-selected="false" aria-expanded="false" role="tab">
Tab title 2
<svg class="icon tab__icon" role="presentation" focusable="false">
<use href="/images/icons-sprite.svg#angle-down"></use>
</svg>
</button>
<div class="
tab__content
" id="tab-2" data-content="tab-2" aria-labelledby="tab-title-2" aria-hidden="true" role="tabpanel">
<div class="lazyload-wrapper ">
<img class="
image
lazyload
" src="data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAABCAQAAABN/Pf1AAAAC0lEQVR42mNkwAIAACoAAgu1Hc4AAAAASUVORK5CYII=" data-src="/images/banner/banner-480_480.png" alt="image alt text">
</div>
</div>
<button class="tab__title " data-tab="tab-3" id="tab-title-3" aria-controls="tab-3" aria-selected="false" aria-expanded="false" role="tab">
Tab title 3
<svg class="icon tab__icon" role="presentation" focusable="false">
<use href="/images/icons-sprite.svg#angle-down"></use>
</svg>
</button>
<div class="
tab__content
" id="tab-3" data-content="tab-3" aria-labelledby="tab-title-3" aria-hidden="true" role="tabpanel">
<p>Pellentesque velit nisl, posuere ac erat nec, iaculis auctor magna. Donec ut elementum mauris. Sed in scelerisque lorem. Cras pretium laoreet vestibulum. In dui mauris, sagittis vitae rhoncus quis, ornare in enim. Vivamus pellentesque ligula sed quam sollicitudin lobortis. Etiam interdum euismod nisi a interdum. Nunc turpis urna, pharetra nec nunc sit amet, consequat porta orci. Suspendisse sit amet dignissim lacus. Quisque vel est pretium, aliquam lacus id, lobortis neque. Nullam non neque mi. Vivamus quis pulvinar mi, in elementum nulla. Etiam neque diam, suscipit vitae luctus et, sollicitudin in turpis. Proin vitae cursus augue, sit amet vestibulum mi. Mauris feugiat justo eget purus fringilla aliquam vitae a massa.</p>
</div>
<button class="tab__title " data-tab="tab-4" id="tab-title-4" aria-controls="tab-4" aria-selected="false" aria-expanded="false" role="tab">
Tab title 4
<svg class="icon tab__icon" role="presentation" focusable="false">
<use href="/images/icons-sprite.svg#angle-down"></use>
</svg>
</button>
<div class="
tab__content
" id="tab-4" data-content="tab-4" aria-labelledby="tab-title-4" aria-hidden="true" role="tabpanel">
<p>Pellentesque velit nisl, posuere ac erat nec, iaculis auctor magna. Donec ut elementum mauris. Sed in scelerisque lorem. Cras pretium laoreet vestibulum. In dui mauris, sagittis vitae rhoncus quis, ornare in enim. Vivamus pellentesque ligula sed quam sollicitudin lobortis. Etiam interdum euismod nisi a interdum. Nunc turpis urna, pharetra nec nunc sit amet, consequat porta orci. Suspendisse sit amet dignissim lacus. Quisque vel est pretium, aliquam lacus id, lobortis neque. Nullam non neque mi. Vivamus quis pulvinar mi, in elementum nulla. Etiam neque diam, suscipit vitae luctus et, sollicitudin in turpis. Proin vitae cursus augue, sit amet vestibulum mi. Mauris feugiat justo eget purus fringilla aliquam vitae a massa.</p>
</div>
<button class="tab__title " data-tab="tab-5" id="tab-title-5" aria-controls="tab-5" aria-selected="false" aria-expanded="false" role="tab">
Tab title 5
<svg class="icon tab__icon" role="presentation" focusable="false">
<use href="/images/icons-sprite.svg#angle-down"></use>
</svg>
</button>
<div class="
tab__content
" id="tab-5" data-content="tab-5" aria-labelledby="tab-title-5" aria-hidden="true" role="tabpanel">
<p>Pellentesque velit nisl, posuere ac erat nec, iaculis auctor magna. Donec ut elementum mauris. Sed in scelerisque lorem. Cras pretium laoreet vestibulum. In dui mauris, sagittis vitae rhoncus quis, ornare in enim. Vivamus pellentesque ligula sed quam sollicitudin lobortis. Etiam interdum euismod nisi a interdum. Nunc turpis urna, pharetra nec nunc sit amet, consequat porta orci. Suspendisse sit amet dignissim lacus. Quisque vel est pretium, aliquam lacus id, lobortis neque. Nullam non neque mi. Vivamus quis pulvinar mi, in elementum nulla. Etiam neque diam, suscipit vitae luctus et, sollicitudin in turpis. Proin vitae cursus augue, sit amet vestibulum mi. Mauris feugiat justo eget purus fringilla aliquam vitae a massa.</p>
</div>
</div>
<script src="/components/raw/tab/tab.js"></script>
<div
class="tab {{#if modifier}}tab--{{modifier}}{{/if}} {{ class }}"
role="tablist"
{{{ attributes }}}
>
{{#each tabs as |tab|}}
<button
class="tab__title {{#if active}}tab__title--active{{/if}} {{ class.title }}"
data-tab="{{ tabId }}"
id="{{ titleId }}"
aria-controls="{{ tabId }}"
aria-selected="{{#if active}}true{{else}}false{{/if}}"
aria-expanded="{{#if active}}true{{else}}false{{/if}}"
role="tab"
>
{{#if icon }}
<span class="tab__title-icon">
{{ render '@icon' icon }}
</span>
{{/if}}
{{ title }}
{{#if ../icon}}
{{ render '@icon' ../icon }}
{{/if}}
</button>
<div
class="
tab__content
{{#if active}}tab__content--active{{/if}}
{{ class.content }}
"
id="{{ tabId }}"
data-content="{{ tabId }}"
aria-labelledby="{{ titleId }}"
aria-hidden="{{#if active}}false{{else}}true{{/if}}"
role="tabpanel"
>
{{#if contentElement}}
{{ render (component contentElement) contentContext }}
{{/if}}
{{#if content}}
{{{ content }}}
{{/if}}
</div>
{{/each}}
</div>
{{#if script}}
<script src="{{static 'tab.js' }}"></script>
{{/if}}
{
"script": true,
"icon": {
"class": "tab__icon",
"id": "angle-down",
"hidden": true
},
"tabs": [
{
"tabId": "tab-1",
"title": "Tab title",
"titleId": "tab-title-1",
"content": "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque pharetra ut magna ornare lacinia. Cras sodales elit ac pellentesque aliquet. Nulla nec viverra turpis. Mauris eget quam interdum, viverra enim eget, ultricies purus. Suspendisse eleifend, turpis id pretium consectetur, massa nunc suscipit elit, a porta neque neque sed ex. Curabitur nec ante non urna rhoncus semper. Maecenas id pulvinar erat. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque mollis sit amet quam id vestibulum. Nunc faucibus quam non venenatis laoreet. Pellentesque eu feugiat tellus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.</p>",
"active": true,
"class": {
"content": "",
"title": ""
}
},
{
"tabId": "tab-2",
"title": "Tab title 2",
"titleId": "tab-title-2",
"contentElement": "image",
"class": {
"content": "",
"title": ""
}
},
{
"tabId": "tab-3",
"title": "Tab title 3",
"titleId": "tab-title-3",
"content": "<p>Pellentesque velit nisl, posuere ac erat nec, iaculis auctor magna. Donec ut elementum mauris. Sed in scelerisque lorem. Cras pretium laoreet vestibulum. In dui mauris, sagittis vitae rhoncus quis, ornare in enim. Vivamus pellentesque ligula sed quam sollicitudin lobortis. Etiam interdum euismod nisi a interdum. Nunc turpis urna, pharetra nec nunc sit amet, consequat porta orci. Suspendisse sit amet dignissim lacus. Quisque vel est pretium, aliquam lacus id, lobortis neque. Nullam non neque mi. Vivamus quis pulvinar mi, in elementum nulla. Etiam neque diam, suscipit vitae luctus et, sollicitudin in turpis. Proin vitae cursus augue, sit amet vestibulum mi. Mauris feugiat justo eget purus fringilla aliquam vitae a massa.</p>",
"class": {
"content": "",
"title": ""
}
},
{
"tabId": "tab-4",
"title": "Tab title 4",
"titleId": "tab-title-4",
"content": "<p>Pellentesque velit nisl, posuere ac erat nec, iaculis auctor magna. Donec ut elementum mauris. Sed in scelerisque lorem. Cras pretium laoreet vestibulum. In dui mauris, sagittis vitae rhoncus quis, ornare in enim. Vivamus pellentesque ligula sed quam sollicitudin lobortis. Etiam interdum euismod nisi a interdum. Nunc turpis urna, pharetra nec nunc sit amet, consequat porta orci. Suspendisse sit amet dignissim lacus. Quisque vel est pretium, aliquam lacus id, lobortis neque. Nullam non neque mi. Vivamus quis pulvinar mi, in elementum nulla. Etiam neque diam, suscipit vitae luctus et, sollicitudin in turpis. Proin vitae cursus augue, sit amet vestibulum mi. Mauris feugiat justo eget purus fringilla aliquam vitae a massa.</p>",
"class": {
"content": "",
"title": ""
}
},
{
"tabId": "tab-5",
"title": "Tab title 5",
"titleId": "tab-title-5",
"content": "<p>Pellentesque velit nisl, posuere ac erat nec, iaculis auctor magna. Donec ut elementum mauris. Sed in scelerisque lorem. Cras pretium laoreet vestibulum. In dui mauris, sagittis vitae rhoncus quis, ornare in enim. Vivamus pellentesque ligula sed quam sollicitudin lobortis. Etiam interdum euismod nisi a interdum. Nunc turpis urna, pharetra nec nunc sit amet, consequat porta orci. Suspendisse sit amet dignissim lacus. Quisque vel est pretium, aliquam lacus id, lobortis neque. Nullam non neque mi. Vivamus quis pulvinar mi, in elementum nulla. Etiam neque diam, suscipit vitae luctus et, sollicitudin in turpis. Proin vitae cursus augue, sit amet vestibulum mi. Mauris feugiat justo eget purus fringilla aliquam vitae a massa.</p>",
"class": {
"content": "",
"title": ""
}
}
]
}
$tab__padding : 0 0 $spacer !default;
$tab__border : $border-base !default;
$tab__title-display : block !default;
$tab__title-size : 72px !default;
$tab__title-width : 100% !default;
$tab__title-max-width\@large : 440px !default;
$tab__title-flex\@large : 1 !default;
$tab__title-padding : $spacer--medium !default;
$tab__title-border : $tab__border !default;
$tab__title-border-width : 0 0 $border-width-base 0 !default;
$tab__title-color : $color-secondary !default;
$tab__title-color--active : $color-primary !default;
$tab__title-background : $bg-color-base !default;
$tab__title-background--active : $gray-light !default;
$tab__title-font-family : $font-family-base !default;
$tab__title-font-size : $font-size-large !default;
$tab__title-font-weight : $font-weight-medium !default;
$tab__title-font-weight--active : $font-weight-bold !default;
$tab__title-text-align : center !default;
$tab__title-text-transform : uppercase !default;
$tab__title-transition : $transition-base !default;
$tab__title-z-index--active : $z-index-initial !default;
$tab__title-z-index--active\@large : $z-index-low !default;
$tab__content-z-index : $z-index-lowest !default;
$tab__content-z-index\@medium : $z-index-low !default;
$tab__content-padding : 64px 0 !default;
$tab__content-padding\@medium : 72px 104px !default;
$tab__content-padding\@large : 72px 80px !default;
$tab__content-padding\@extra-large : 72px 112px !default;
$tab__content-padding--secondary : 64px 0 !default;
$tab__content-width : 100% !default;
$tab__content-line-height : 32px !default;
$tab__content-border--active : $tab__title-border !default;
$tab__content-border--active\@large: none !default;
$tab__content-border-width--active : 0 0 $border-width-base 0 !default;
$tab__icon-display : block !default;
$tab__icon-display\@large : none !default;
$tab__icon-position : absolute !default;
$tab__icon-margin : auto !default;
$tab__icon-right : $spacer--medium !default;
$tab__icon-fill : $color-secondary !default;
$tab__icon-fill--active : $color-primary !default;
$tab__icon-transform--active : rotate(180deg) !default;
@import 'tab-variables';
.tab {
padding: $tab__padding;
@include mq($screen-l) {
display: flex;
flex-flow: row wrap;
justify-content: center;
}
&__title {
position: relative;
display: $tab__title-display;
width: $tab__title-width;
height: $tab__title-size;
padding: $tab__title-padding;
border: $tab__title-border;
border-width: $tab__title-border-width;
background: $tab__title-background;
color: $tab__title-color;
font-family: $tab__title-font-family;
font-size: $tab__title-font-size;
font-weight: $tab__title-font-weight;
text-align: $tab__title-text-align;
text-transform: $tab__title-text-transform;
transition: $tab__title-transition;
cursor: pointer;
@include mq($screen-l) {
max-width: $tab__title-max-width\@large;
}
@include mq($screen-l) {
flex: $tab__title-flex\@large;
order: -1;
}
.tab__icon {
fill: $tab__icon-fill;
pointer-events: none;
}
&:hover,
&.focus-visible,
&--active {
background: $tab__title-background--active;
color: $tab__title-color--active;
font-weight: $tab__title-font-weight--active;
z-index: $tab__title-z-index--active;
@include mq($screen-l) {
z-index: $tab__title-z-index--active\@large;
}
.tab__icon {
fill: $tab__icon-fill--active;
}
}
&--active {
.tab__icon {
transform: $tab__icon-transform--active;
}
}
.counter {
&:before {
content: "(";
}
&:after {
content: ")";
}
}
}
&__icon {
display: $tab__icon-display;
position: $tab__icon-position;
top: 0;
bottom: 0;
right: $tab__icon-right;
margin: $tab__icon-margin;
@include mq($screen-l) {
display: $tab__icon-display\@large;
}
}
&__content {
position: relative;
display: none;
z-index: $tab__content-z-index;
width: $tab__content-width;
padding: $tab__content-padding;
line-height: $tab__content-line-height;
opacity: 0;
overflow: hidden;
@include mq($screen-m) {
padding: $tab__content-padding\@medium;
flex-basis: 100%;
z-index: $tab__content-z-index\@medium;
}
@include mq($screen-l) {
padding: $tab__content-padding\@large;
}
@include mq($screen-xl) {
padding: $tab__content-padding\@extra-large;
}
&--active {
display: block;
opacity: 1;
z-index: 1;
&:not(:nth-last-child(1)) {
border: $tab__content-border--active;
border-width: $tab__content-border-width--active;
@include mq($screen-l) {
border: $tab__content-border--active\@large;
border-width: $tab__content-border-width--active;
}
}
}
&--secondary {
padding: $tab__content-padding--secondary;
}
// It's necessary for display .tooltip in tab in PDP
&.additional {
overflow: initial;
}
}
}
'use strict';
(function() { // eslint-disable-line
const tab = document.querySelector('.tab');
const activeTitleClass = 'tab__title--active';
const activeContentClass = 'tab__content--active';
const children = Array.from(tab.children);
const titles = [...tab.querySelectorAll('.tab__title')];
const mqBreakpoint = window.matchMedia('screen and (min-width: 768px)');
function setActiveTab(elem) {
const tabTitle = elem.dataset.tab;
children.forEach((item) => {
resetItems(item);
if (
item.classList.contains('tab__content')
&& tabTitle === item.dataset.content
) {
item.classList.add(activeContentClass);
item.setAttribute('aria-hidden', false);
}
elem.classList.add(activeTitleClass);
elem.setAttribute('aria-expanded', true);
elem.setAttribute('aria-selected', true);
});
}
function keyboardForward(currentTitleIndex) {
if (currentTitleIndex === titles.length - 1) {
titles[0].focus();
}
else {
titles[currentTitleIndex + 1].focus();
}
}
function keyboardBackward(currentTitleIndex) {
if (currentTitleIndex === 0) {
titles[titles.length - 1].focus();
}
else {
titles[currentTitleIndex - 1].focus();
}
}
function resetItems(item) {
if (item.classList.contains('tab__content')) {
item.classList.remove(activeContentClass);
item.setAttribute('aria-hidden', true);
}
else {
item.classList.remove(activeTitleClass);
item.setAttribute('aria-expanded', false);
item.setAttribute('aria-selected', false);
}
}
function setKeyboardNav(e) {
let currentTitle = e.target;
let currentTitleIndex = titles.indexOf(currentTitle);
let isAccordion = currentTitle.parentNode.classList.contains('tab--accordion');
if (mqBreakpoint.matches && !isAccordion) {
if (e.which == 39) {
e.preventDefault();
keyboardForward(currentTitleIndex);
}
else if (e.which == 37) {
e.preventDefault();
keyboardBackward(currentTitleIndex);
}
}
else {
if (e.which == 38) {
e.preventDefault();
keyboardBackward(currentTitleIndex);
}
else if (e.which == 40) {
e.preventDefault();
keyboardForward(currentTitleIndex);
}
}
}
titles.forEach(item => {
item.addEventListener('click', (e) => {
setActiveTab(e.target);
});
item.addEventListener('keydown', (e) => {
setKeyboardNav(e);
})
});
})();
Our components is accordion on mobile and tabs on wider screens, so we have to implement a11y feature to be used in both cases:
role="tablist"
on the element that serves as the container for the set of tabsrole="tab"
on tab elementrole="tabpanel"
on tab contentbuttons
elements as a labels/headings of tabsaria-expanded
- set to true
if tab is open, to false
when it’s closedaria-controls
where value it’s an id
of content tab elementaria-selected
set to false
when tab is closed and to true
if it’s openaria-hidden
attribute set to true
if tab is closed and to false
if it’s openaria-labelledby
with value of tab title id