Exhibit 01 of 17
Tabs, from radio buttons
Click a tab and its panel shows. Each tab is the label of a hidden radio button, and :checked ~ shows the panel that goes with the checked one.
The exhibit
The bench
Longer than it looks and shorter than he needs. Tweezers on the left, glue on the right, patience in the second drawer.
The lamp
Always on. It has been on since before the workshop, possibly before the lamp. Nobody has found the switch.
The shelf
A sardine tin with a sea in it, a walnut with a theatre in it, and a pocket watch that is mostly weather.
How it works
The three radio buttons come first in the HTML, then the tab bar of labels, then the panels. Radio buttons in one group can only have one checked, which is exactly how tabs behave. #tab-lamp:checked ~ #panel-lamp means “the lamp panel, if it comes after a checked lamp radio”, so the CSS only has to hide every panel and show that one.
The radios are invisible but still on the page, so they can take keyboard focus; their focus ring is drawn on the label instead.
The key CSS
Cut from this exhibit’s stylesheet as it is served.
/* every panel is hidden until its radio is checked */
.x-tabs .panel { display: none; }
#tab-bench:checked ~ #panel-bench,
#tab-lamp:checked ~ #panel-lamp,
#tab-shelf:checked ~ #panel-shelf { display: block; }
/* the checked radio's label is the current tab */
#tab-bench:checked ~ .tab-bar [for=tab-bench],
#tab-lamp:checked ~ .tab-bar [for=tab-lamp],
#tab-shelf:checked ~ .tab-bar [for=tab-shelf] {
border-color: var(--ink); background: var(--ink); color: var(--paper);
}
/* the radio is invisible, so its focus ring goes on the label */
#tab-bench:focus-visible ~ .tab-bar [for=tab-bench],
#tab-lamp:focus-visible ~ .tab-bar [for=tab-lamp],
#tab-shelf:focus-visible ~ .tab-bar [for=tab-shelf] {
outline: 3px solid var(--focus); outline-offset: 3px;
}
Accessibility
Better than it sounds: radios are real form controls, so Tab reaches the group, the arrow keys change tab, and each one is announced by its label. But a screen reader says “radio button, 2 of 3”, not “tab, 2 of 3”, and the panels aren’t announced as tab panels. The ARIA tab pattern needs a script to move aria-selected and focus; CSS can’t set attributes. This is one of the hacks that is nearly as good as the script, and not quite.
Browser support
:checked + ~Works in this browser.Not in this browser: Nothing to fall back from; every browser has had it for years. Checked 2026-10-14: Chromium 149 yes, Firefox 141 yes.
