Last active
September 7, 2024 13:26
-
-
Save H-ymt/67f967775ec0439b639baeeb2036a69c to your computer and use it in GitHub Desktop.
アクセシビリティを考慮したタブUI
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div class="tabs-container"> | |
<div class="tabs-list" role="tablist" aria-label="サンプルタブ"> | |
<button class="tab" role="tab" aria-selected="true" aria-controls="panel-1" id="tab-1" tabindex="0"> | |
タブ1 | |
</button> | |
<button class="tab" role="tab" aria-selected="false" aria-controls="panel-2" id="tab-2" tabindex="-1"> | |
タブ2 | |
</button> | |
<button class="tab" role="tab" aria-selected="false" aria-controls="panel-3" id="tab-3" tabindex="-1"> | |
タブ3 | |
</button> | |
</div> | |
<div id="panel-1" class="tab-panel" role="tabpanel" aria-labelledby="tab-1"> | |
<h2>タブ1の内容</h2> | |
<p>これはタブ1のコンテンツ</p> | |
</div> | |
<div id="panel-2" class="tab-panel is-hidden" role="tabpanel" aria-labelledby="tab-2"> | |
<h2>タブ2の内容</h2> | |
<p>これはタブ2のコンテンツ</p> | |
</div> | |
<div id="panel-3" class="tab-panel is-hidden" role="tabpanel" aria-labelledby="tab-3"> | |
<h2>タブ3の内容</h2> | |
<p>これはタブ3のコンテンツ</p> | |
</div> | |
</div> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.tab-panel.is-hidden { | |
display: none; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
window.addEventListener("DOMContentLoaded", () => { | |
const tabInterface = { | |
tabs: document.querySelectorAll('[role="tab"]'), | |
tabLists: document.querySelectorAll('[role="tablist"]'), | |
tabPanels: document.querySelectorAll('[role="tabpanel"]'), | |
init() { | |
this.tabs.forEach((tab) => { | |
tab.addEventListener("click", this.changeTabs.bind(this)); | |
}); | |
this.tabLists.forEach(this.setupKeyboardNavigation.bind(this)); | |
const initialTab = document.querySelector('[aria-selected="true"]'); | |
if (initialTab) { | |
this.activateTab(initialTab); | |
} | |
}, | |
changeTabs(e) { | |
const target = e.currentTarget; // e.targetからe.currentTargetに変更 | |
this.activateTab(target); | |
}, | |
activateTab(tab) { | |
const allTabs = document.querySelectorAll('[role="tab"]'); | |
const allTabPanels = document.querySelectorAll('[role="tabpanel"]'); | |
allTabs.forEach((t) => { | |
t.setAttribute("aria-selected", "false"); | |
t.setAttribute("tabindex", "-1"); | |
}); | |
tab.setAttribute("aria-selected", "true"); | |
tab.setAttribute("tabindex", "0"); | |
allTabPanels.forEach((p) => p.classList.add("is-hidden")); | |
const targetPanel = document.getElementById( | |
tab.getAttribute("aria-controls") | |
); | |
if (targetPanel) targetPanel.classList.remove("is-hidden"); | |
}, | |
setupKeyboardNavigation(tabList) { | |
let tabFocus = 0; | |
const tabs = tabList.querySelectorAll('[role="tab"]'); | |
tabList.addEventListener("keydown", (e) => { | |
if (e.key === "ArrowLeft" || e.key === "ArrowRight") { | |
tabs[tabFocus].setAttribute("tabindex", "-1"); | |
if (e.key === "ArrowLeft") { | |
tabFocus = (tabFocus - 1 + tabs.length) % tabs.length; | |
} else { | |
tabFocus = (tabFocus + 1) % tabs.length; | |
} | |
tabs[tabFocus].setAttribute("tabindex", "0"); | |
tabs[tabFocus].focus(); | |
} | |
}); | |
}, | |
}; | |
tabInterface.init(); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment