Welcome to Vanilla Breeze
This bell pulls live notifications from /go/notify/messages — the same contract documented at /docs/concepts/service-contracts/. Static articles like this one are the no-JS / no-backend fallback.
This bell pulls live notifications from /go/notify/messages — the same contract documented at /docs/concepts/service-contracts/. Static articles like this one are the no-JS / no-backend fallback.
Style checkboxes as selectable pill chips for tag-based filtering and multi-select. Pure CSS with optional JavaScript for max selection limits.
The data-toggle-tags attribute transforms a fieldset of checkboxes into selectable pill-shaped tags. The styling is pure CSS via :has(:checked) — JavaScript is only loaded when you need a max selection limit via data-max.
<fieldset data-toggle-tags> <legend>Topics</legend> <label><input type="checkbox" name="topics" value="ai"> AI / ML</label> <label><input type="checkbox" name="topics" value="web"> Web Dev</label> <label><input type="checkbox" name="topics" value="mobile"> Mobile</label></fieldset>
Add data-toggle-tags to a <fieldset> containing checkbox inputs inside labels. The mechanism is primarily CSS:
<label> is styled as a pill chip with padding, border, and rounded cornersopacity: 0:has(:checked) detects when a checkbox is selected and applies the active styleWhen data-max is set, a small JavaScript module is loaded. It listens for checkbox changes and disables unchecked checkboxes once the limit is reached, re-enabling them when selections are removed.
| Attribute | Type | Description |
|---|---|---|
data-toggle-tags |
boolean | Placed on a <fieldset>. Enables pill chip styling for child checkbox labels. |
data-max |
number | Maximum number of selections allowed. When reached, unchecked checkboxes are disabled. Requires JavaScript. |
Without data-max, toggle tags are entirely CSS-driven. Users can select and deselect any number of tags freely.
<fieldset data-toggle-tags> <legend>Topics</legend> <label><input type="checkbox" name="topics" value="ai"> AI / ML</label> <label><input type="checkbox" name="topics" value="web"> Web Dev</label> <label><input type="checkbox" name="topics" value="mobile"> Mobile</label></fieldset>
Add data-max to cap the number of selections. When the limit is reached, remaining unchecked tags are disabled and visually muted. Deselecting a tag re-enables the others.
<fieldset data-toggle-tags data-max="3"> <legend>Pick up to 3</legend> <label><input type="checkbox" name="skills" value="js"> JavaScript</label> <label><input type="checkbox" name="skills" value="py"> Python</label> <label><input type="checkbox" name="skills" value="go"> Go</label> <label><input type="checkbox" name="skills" value="rust"> Rust</label> <label><input type="checkbox" name="skills" value="ts"> TypeScript</label> <label><input type="checkbox" name="skills" value="ruby"> Ruby</label></fieldset>
Add the native checked attribute to pre-select tags on load. This works with or without data-max.
<fieldset data-toggle-tags> <legend>Interests</legend> <label><input type="checkbox" name="interest" value="music" checked> Music</label> <label><input type="checkbox" name="interest" value="film"> Film</label> <label><input type="checkbox" name="interest" value="books" checked> Books</label> <label><input type="checkbox" name="interest" value="sports"> Sports</label></fieldset>
Toggle tags work naturally in filter forms. The checkboxes submit as standard form values, making server-side filtering straightforward.
<form> <fieldset data-toggle-tags> <legend>Filter by category</legend> <label><input type="checkbox" name="cat" value="design"> Design</label> <label><input type="checkbox" name="cat" value="dev"> Development</label> <label><input type="checkbox" name="cat" value="marketing"> Marketing</label> <label><input type="checkbox" name="cat" value="product"> Product</label> </fieldset> <button type="submit">Apply filters</button></form>
Because toggle tags use real checkboxes, they participate fully in form behavior without JavaScript:
name=value pairs<button type="reset"> restores original checked statesrequired works on individual checkboxesnew FormData(form) includes all selected tagsThe pill chip appearance is driven entirely by CSS. The :has(:checked) selector eliminates the need for JavaScript class toggling.
/* Tags use CSS :has() — no JS needed for styling */[data-toggle-tags] label { display: inline-flex; align-items: center; padding: var(--size-2xs) var(--size-s); border: 1px solid var(--color-border); border-radius: var(--radius-pill); cursor: pointer; transition: background-color 0.15s, border-color 0.15s;} /* Checked state via :has() */[data-toggle-tags] label:has(:checked) { background: var(--color-primary); border-color: var(--color-primary); color: var(--color-on-primary);} /* Hide the checkbox visually */[data-toggle-tags] input[type="checkbox"] { position: absolute; opacity: 0; width: 0; height: 0;} /* Disabled state when max reached */[data-toggle-tags] label:has(:disabled:not(:checked)) { opacity: 0.5; cursor: not-allowed;}
The checked state swaps the background to --color-primary and the text to --color-on-primary. Disabled tags (from data-max) use reduced opacity.
Fieldsets added to the DOM after page load are automatically enhanced via a MutationObserver when data-max is present. No manual initialization is needed. Tags without data-max require no JavaScript at all.
Pick up to 2 <label><input type="checkbox" name="opt" value="a"> Option A</label> <label><input type="checkbox" name="opt" value="b"> Option B</label> <label><input type="checkbox" name="opt" value="c"> Option C</label>`;document.body.appendChild(fieldset);// fieldset is ready — no manual init needed/code-block
<input type="checkbox"> elements provide full keyboard support — Tab to navigate, Space to toggle<fieldset> and <legend> provide a group label announced by screen readersdata-max) is announced via the native disabled attribute:focus-visible on the label for clear keyboard navigation