1. The Classic :checked Limitation
Pure CSS can already build click interactions, but sibling selectors require the controlled panels to come after the inputs in a shared structure.
<div class="limited-root">
<input type="radio" id="limitOne" name="limited" checked>
<input type="radio" id="limitTwo" name="limited">
<div class="limited-layout">
<div class="limited-controls">
<label for="limitOne">Sibling rule</label>
<label for="limitTwo">DOM restriction</label>
</div>
<div class="limited-panels">
<section class="limited-panel panel-one">Panel one is visible.</section>
<section class="limited-panel panel-two">Panel two is visible.</section>
</div>
</div>
</div>
<style>
/* Only following siblings can be selected. */
#limitOne:checked ~ .limited-panels .panel-one,
#limitTwo:checked ~ .limited-panels .panel-two {
display: block;
}
</style>
2. Parent Element Responds to Radio State
The smart-for rule is simple: when an input is checked, every element whose for value matches that input’s id receives .active.
<ul class="option-list">
<li for="item1"><input type="radio" id="item1" name="item" checked>Option 1</li>
<li for="item2"><input type="radio" id="item2" name="item">Option 2</li>
<li for="item3"><input type="radio" id="item3" name="item">Option 3</li>
<li for="item4"><input type="radio" id="item4" name="item">Option 4</li>
<li for="item5"><input type="radio" id="item5" name="item">Option 5</li>
</ul>
<style>
.option-list li.active {
color: white;
background: #0f766e;
}
</style>
- Option 1
- Option 2
- Option 3
- Option 4
- Option 5
3. Sidebar with One Checkbox
A checkbox represents open or closed. Labels provide native toggling, while .aside.active controls visibility.
<label class="ui-button">
<input type="checkbox" id="zxxAside" hidden>
Click me to show the sidebar
</label>
<aside class="aside" for="zxxAside">
<label for="zxxAside" class="aside-overlay"></label>
<div class="aside-content">Click the black overlay to collapse</div>
</aside>
<style>
.aside { visibility: hidden; }
.aside.active { visibility: visible; }
</style>
The overlay is a label for the same checkbox, so clicking it unchecks the control.
4. Dropdown List
The menu can live inside the dropdown wrapper here, but the same for/id association would still work if it moved elsewhere.
<div class="dropdown-demo">
<label class="dropdown-toggle">
<input type="checkbox" id="cityMenu" hidden>
Choose a city
</label>
<div class="dropdown-menu" for="cityMenu">
<label for="cityMenu">Shanghai</label>
<label for="cityMenu">Hangzhou</label>
<label for="cityMenu">Shenzhen</label>
</div>
</div>
<style>
.dropdown-menu {
opacity: 0;
visibility: hidden;
}
.dropdown-menu.active {
opacity: 1;
visibility: visible;
}
</style>
5. Tab Switching Without Strange Hierarchy
Tab buttons and tab panels can be organized normally. Each visual element listens to the radio id it cares about.
<input class="tab-radios" type="radio" id="tabIdea" name="tabs" checked>
<input class="tab-radios" type="radio" id="tabDemo" name="tabs">
<input class="tab-radios" type="radio" id="tabCaveat" name="tabs">
<nav class="tab-nav">
<label for="tabIdea">Idea</label>
<label for="tabDemo">Demo</label>
<label for="tabCaveat">Caveat</label>
</nav>
<section class="tab-panel" for="tabIdea">The label and panel both become active.</section>
<section class="tab-panel" for="tabDemo">No sibling selector is needed.</section>
<section class="tab-panel" for="tabCaveat">This is powerful, but not semantic magic.</section>
Idea
The label and panel both become active because they point to the checked radio.
Demo
No sibling selector is needed, so the source structure can stay readable.
Caveat
This is powerful for interaction glue, but it still needs thoughtful HTML and accessibility decisions.
6. The Synchronization Engine
The helper watches native clicks, scripted .checked assignments, attribute changes, radio-group changes, and newly inserted associated elements.
<script>
(function () {
var selector = 'input[type="radio"], input[type="checkbox"]';
function sync(input) {
if (!input || !input.id || !input.matches(selector)) return;
if (input.type === 'radio' && input.name) {
document.querySelectorAll('input[type="radio"][name="' + CSS.escape(input.name) + '"]').forEach(syncOne);
} else {
syncOne(input);
}
}
function syncOne(input) {
if (!input.id) return;
document.querySelectorAll('[for="' + CSS.escape(input.id) + '"]').forEach(function (node) {
if (node !== input) node.classList.toggle('active', input.checked);
});
}
document.addEventListener('click', function (event) {
var target = event.target.closest(selector + ', [for]');
if (!target) return;
requestAnimationFrame(function () {
sync(target.matches(selector) ? target : document.getElementById(target.getAttribute('for')));
});
});
var checked = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'checked');
Object.defineProperty(HTMLInputElement.prototype, 'checked', {
get: checked.get,
set: function (value) {
checked.set.call(this, value);
sync(this);
}
});
new MutationObserver(function (records) {
records.forEach(function (record) {
if (record.type === 'attributes') sync(record.target);
document.querySelectorAll(selector).forEach(sync);
});
}).observe(document.documentElement, {
childList: true,
subtree: true,
attributes: true,
attributeFilter: ['checked', 'for', 'id', 'name']
});
document.querySelectorAll(selector).forEach(sync);
})();
</script>
#engineBox.