Tabset
An in-page tab set with no JavaScript and no IDs. Inside a div class="tabset",
a label wrapping a radio is a tab, and the element right after it is that
tab's content. The radios share a name, so only one is ever selected, and the stylesheet
shows that tab's content and hides the rest.
<div class="tabset">
<label><input type="radio" name="view" checked> Overview</label>
<div>
…the Overview content…
</div>
<label><input type="radio" name="view"> Rules</label>
<div>
…the Rules content…
</div>
</div>
A tab set
Overview
The element straight after a tab holds its content. It drops onto its own row below the strip and takes the panel surface, so the tab and its content read as one unit.
Rules
Pick another tab and the stylesheet swaps which content shows. The radios carry the state, so it holds without a line of script.
Members
Every tab follows the same shape: a label with a radio, then the block of content it reveals.
Log
Mark one radio checked and that tab opens on load.
<div class="tabset">
<label><input type="radio" name="tabs-basic" checked> Overview</label>
<div>
<h3>Overview</h3>
<p>…</p>
</div>
<label><input type="radio" name="tabs-basic"> Rules</label>
<div>
<h3>Rules</h3>
<p>…</p>
</div>
</div>
The content is any element
The content carries no class, so it is whatever element the content needs: a
div of mixed content, a bare p, a table, a
form. The stylesheet only cares that it sits right after the tab.
A single paragraph can be the whole content, with no wrapper around it.
| Login | Group |
|---|---|
| ada | Editors |
| grace | Viewers |
<div class="tabset">
<label><input type="radio" name="tabs-el" checked> Summary</label>
<p>A single paragraph can be the whole content.</p>
<label><input type="radio" name="tabs-el"> People</label>
<div>
<table> … </table>
</div>
<label><input type="radio" name="tabs-el"> Actions</label>
<div class="buttons"> … </div>
</div>
Reading the selection
The tabs are a radio group, so a script reads the chosen tab from the checked
radio. Give each radio a value and listen for change.
<label><input type="radio" name="view" value="overview" checked> Overview</label>
<label><input type="radio" name="view" value="rules"> Rules</label>
<script>
const tabs = document.querySelector('.tabs')
tabs.addEventListener('change', e => console.log(e.target.value))
tabs.querySelector('input:checked').value // the current tab
</script>
Nested tabs
Tabs nest: put a second set inside a tab's content and it runs on its own, because
the child combinator keeps each set's rules to its own direct children. The one thing
to settle is grouping. Radios group by a shared name within a form, so wrap a set in a
form and every set on the page, outer and inner, can reuse the one name.
A form cannot nest, so the outer set stays a div and each
inner set is the form. The inner sets below are vertical.
Overview
Each tab here opens a vertical set of its own, kept apart by its form.
Rules
<div class="tabset">
<label><input type="radio" name="tab" checked> Overview</label>
<div>
<h3>Overview</h3>
<form class="tabset vertical">
<label><input type="radio" name="tab" checked> Details</label>
<div>…</div>
<label><input type="radio" name="tab"> History</label>
<div>…</div>
</form>
</div>
<label><input type="radio" name="tab"> Rules</label>
<div> … </div>
</div>