Accessible Tabs
by ninty9notout
HTML
<h2 id="heading">Operating Systems</h2>
<div class="tablist" role="tablist" aria-labelledby="heading">
<label class="tab">
<input type="radio" class="radio" name="tab" value="iOS" role="tab" aria-selected="true" aria-controls="tabpanel-1" checked>
<span>iOS</span>
</label>
<label class="tab">
<input type="radio" class="radio" name="tab" value="Android" role="tab" aria-selected="false" aria-controls="tabpanel-2">
<span>Android</span>
</label>
<label class="tab">
<input type="radio" class="radio" name="tab" value="HarmonyOS" role="tab" aria-selected="false" aria-controls="tabpanel-3">
<span>HarmonyOS</span>
</label>
<label class="tab">
<input type="radio" class="radio" name="tab" value="KaiOS" role="tab" aria-selected="false" aria-controls="tabpanel-4">
<span>KaiOS</span>
</label>
</div>
<div class="tabpanel is-selected" id="tabpanel-1" role="tabpanel">
<ul>
<li>Developed by Apple, iOS is exclusive to Apple's devices like the iPhone and iPad.</li>
<li>Known for its sleek design, privacy focus, and seamless integration with the Apple ecosystem.</li>
<li>iOS updates are centralized, making them available to all Apple users simultaneously.</li>
</ul>
</div>
<div class="tabpanel" id="tabpanel-2" role="tabpanel">
<ul>
<li>Developed by Google, Android is the most widely used smartphone OS globally.</li>
<li>It is open-source and allows manufacturers to customize the software for their devices.</li>
<li>Major brands using Android include Samsung, Google, Xiaomi, Oppo, and Huawei.</li>
</ul>
</div>
<div class="tabpanel" id="tabpanel-3" role="tabpanel">
<ul>
<li>Developed by Huawei, HarmonyOS is a relatively new operating system, designed as a multi-device platform.</li>
<li>Initially launched for smart TVs and other IoT devices, it has started appearing on Huawei smartphones due to...
SCSS
@mixin visually-hidden() {
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
&:not(caption) {
position: absolute;
}
}
:focus-visible {
outline: 2px solid #f0f;
outline-offset: 2px;
}
.tab {
display: inline-block;
padding: 10px 20px;
z-index: 1;
border-bottom: 1px solid transparent;
margin-bottom: -1px;
&:hover {
border-bottom-color: rgba(255, 255, 255, 1);
}
&:has(input:checked) {
border-bottom-color: rgba(255, 0, 0, 1);
}
}
.radio {
@include visually-hidden();
}
.tabpanel {
padding-top: 10px;
border-top: 1px solid rgba(255, 255, 255, .5);
&:not(.is-selected) {
display: none;
}
}
JavaScript
document.querySelectorAll('.tab input').forEach(input => {
input.addEventListener('change', event => {
// Hide previously selected tab panel
document.querySelector('.is-selected').classList.remove('is-selected');
// Switch aria selected for previously selected tab
document.querySelector('[aria-selected="true"]').setAttribute('aria-selected', 'false');
// Grab current tab
const tab = event.currentTarget;
const tabpanel = tab.getAttribute('aria-controls');
// Set current active
tab.setAttribute('aria-selected', 'true');
document.getElementById(tabpanel).classList.add('is-selected');
});
});