Primitive
Checkbox Hybrid
A boolean toggle wrapped around a native <input type="checkbox">. Custom-styled control, native semantics, full keyboard and screen-reader support out of the box. Indeterminate state included.
About
Overview
Checkbox is a CSS-only enhancement over the native input. The actual checkbox is the hidden <input> — keyboard, screen readers, and form submission all use the platform's standard behavior. RenDS only paints the visual control on top via .ren-checkbox-control.
Use a Switch instead when the checkbox represents an immediate setting that takes effect right away (notifications on/off, dark mode). Use a Checkbox for things that get committed on form submit.
Live
Demo
<label class="ren-checkbox">
<input type="checkbox">
<span class="ren-checkbox-control"></span>
<span>Subscribe to the weekly digest</span>
</label>
States
Variants
Reference
API
CSS classes
| Class | Effect |
|---|---|
.ren-checkbox | The label wrapper. Inline-flex layout with the control + text. Clicking anywhere in the label toggles the input. |
.ren-checkbox-control | The painted box. Sits next to the hidden input and listens to :checked via the adjacent sibling selector. |
.ren-checkbox > input[type="checkbox"] | The native input. Visually hidden but keyboard- and screen-reader-accessible. Submits with the form like any other checkbox. |
States handled by CSS
| State | Selector |
|---|---|
| Checked | input:checked + .ren-checkbox-control (filled with accent color, white check mark) |
| Indeterminate | input:indeterminate + .ren-checkbox-control (filled with a horizontal bar) |
| Hover | .ren-checkbox:hover > .ren-checkbox-control (border darkens) |
| Focus visible | input:focus-visible + .ren-checkbox-control (focus ring) |
| Disabled | .ren-checkbox:has(input:disabled) (opacity reduced, cursor not-allowed) |
No JavaScript or Web Component — every state is pure CSS.
Inclusive by default
Accessibility
Because the actual control is a real <input type="checkbox">, every accessibility behavior comes from the platform: Tab focus, Space to toggle, screen reader announcement of state, native form participation.
Keyboard
Always wrap the input in the label. The pattern <label class="ren-checkbox"><input>…</label> means the click target is the entire label — not just the small box. That's a 44 px touch target without any extra work.
Indeterminate state
Set programmatically: checkbox.indeterminate = true. Use it for parent checkboxes that summarize a mixed group of children. Any user interaction (click or Space) clears the indeterminate flag.
Patterns
Examples
Select-all with indeterminate parent
const all = document.querySelector('#all');
const items = document.querySelectorAll('input[name="items"]');
const sync = () => {
const checked = Array.from(items).filter(i => i.checked);
all.checked = checked.length === items.length;
all.indeterminate = checked.length > 0 && checked.length < items.length;
};
all.addEventListener('change', () => {
items.forEach(i => i.checked = all.checked);
});
items.forEach(i => i.addEventListener('change', sync));
sync();