techlab / baigie


タブ機能の作り方【アクセシブルな実装シリーズ】 | techlab / baigie
株式会社ベイジのエンジニアチームがお届けする技術情報、チームの取り組みの紹介、お役立ち小話等に関する情報発信メディアです。
<div class="tab-area">
<h2 id="tablist-label">タブ見本項目一覧</h2>
<div class="tab-list" role="tablist" aria-labelledby="tablist-label">
<button class="tab -active js-tab" type="button" role="tab" id="tab1" aria-controls="tab-panel1"
aria-selected="true">タブ1</button>
<button class="tab js-tab" type="button" role="tab" id="tab2" aria-controls="tab-panel2" aria-selected="false"
tabindex="-1">タブ2</button>
<button class="tab js-tab" type="button" role="tab" id="tab3" aria-controls="tab-panel3" aria-selected="false"
tabindex="-1">タブ3</button>
</div>
<div id="tab-panel1" class="tab-panel js-tab-panel -active" role="tabpanel" tabindex="0" aria-labelledby="tab1">
<p>
タブパネル1の内容
</p>
</div>
<div id="tab-panel2" class="tab-panel js-tab-panel" role="tabpanel" tabindex="0" aria-labelledby="tab2">
<p>
タブパネル2の内容
</p>
</div>
<div id="tab-panel3" class="tab-panel js-tab-panel" role="tabpanel" tabindex="0" aria-labelledby="tab3">
<p>
タブパネル3の内容
</p>
</div>
</div>.tab-area {
max-width: 600px;
margin-right: auto;
margin-left: auto;
}
.tab-list {
display: flex;
column-gap: 2px;
}
.tab {
cursor: pointer;
flex: 1;
padding-top: 10px;
padding-bottom: 10px;
border: 1px solid #666;
}
.tab.-active {
background-color: #fff;
}
.tab-panel {
padding: 20px;
display: none;
border: 1px solid #666;
line-height: 1.75;
}
.tab-panel.-active {
display: block;
}const tabs = document.querySelectorAll('.js-tab')
function tabSwitch(){
let tabsArray = Array.prototype.slice.call(tabs);
let index = tabsArray.indexOf(this);
const resetTab = function(){
document.querySelector('.js-tab.-active').classList.remove('-active');
document.querySelector('.js-tab[aria-selected=true]').removeAttribute('aria-selected');
document.querySelectorAll('.js-tab').forEach((elm)=>{
elm.tabIndex = -1;
});
document.querySelector('.js-tab-panel.-active').classList.remove('-active');
}
const setTab = function(tab,tabpanel) {
tab.classList.add('-active');
tab.tabIndex = 0;
tab.setAttribute('aria-selected',true);
tabpanel.classList.add('-active');
}
if (event.type == 'keyup') {
if(event.key === 'ArrowRight') {
if(tabsArray[index + 1]) {
tabsArray[index + 1].focus();
resetTab();
setTab(tabsArray[index + 1],document.querySelectorAll('.js-tab-panel')[index + 1]);
} else {
tabsArray[0].focus();
resetTab();
setTab(tabsArray[0], document.querySelectorAll('.js-tab-panel')[0]);
};
};
if(event.key === 'ArrowLeft') {
if(tabsArray[index - 1]) {
tabsArray[index - 1].focus();
resetTab();
setTab(tabsArray[index - 1], document.querySelectorAll('.js-tab-panel')[index - 1])
} else {
let lastTab = tabsArray.pop();
lastTab.focus();
resetTab();
setTab(lastTab, Array.prototype.slice.call(document.querySelectorAll('.js-tab-panel')).pop());
};
};
}
if (event.type == 'click') {
resetTab();
setTab(this, document.querySelectorAll('.js-tab-panel')[index]);
}
};
tabs.forEach((tab)=>{
tab.addEventListener('click',tabSwitch);
tab.addEventListener('keyup',tabSwitch);
});