Toggle Group
The group is radio buttons in disguise. Each option is a <label> with an <input type="radio"> inside, shrunk away visually. You keep the arrow keys, FormData and the screen reader saying “2 of 3”, without having to rewrite any of it.
How to use it
Section titled “How to use it”<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.36.0/src/tokens/tokens.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.36.0/src/components/css/toggle-group/toggle-group.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.36.0/src/components/css/sr-only/sr-only.css"><!-- Or everything in one file: https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.36.0/dist/lotek.css --><fieldset class="lt-toggle-group"><legend class="lt-sr-only">View</legend>
<label class="lt-toggle-group__option"> <input type="radio" name="view" value="list" checked /> List</label><label class="lt-toggle-group__option"> <input type="radio" name="view" value="map" /> Map</label><label class="lt-toggle-group__option"> <input type="radio" name="view" value="calendar" /> Calendar</label></fieldset>import "@lo-tek/interfaces/tokens.css"import "@lo-tek/interfaces/toggle-group.css"import "@lo-tek/interfaces/sr-only.css"lt is used in two ways, and which one depends on whether you create the element or find it.
If you create the markup, spread the attributes in. That is the way in React, Astro and anything else that renders:
import { lt } from "@lo-tek/interfaces/react"
<fieldset {...lt.toggleGroup()}> <legend {...lt.srOnly()}>View</legend> <label className={lt.toggleGroup.option}> <input type="radio" name="view" value="list" defaultChecked /> List </label></fieldset>The import is from /react here, since the block is JSX. From there the keys are className and htmlFor. In Astro and anything else without React, import @lo-tek/interfaces and you get class and for.
If the element is already there, set them on it. That is the way when you enhance HTML a server or a template has sent:
import { lt } from "@lo-tek/interfaces"
const group = document.querySelector<HTMLFieldSetElement>("#view")if (!group) throw new Error("element not found")
lt.setAttributes(group, lt.toggleGroup())lt.toggleGroup.option gives the class for each option. You read the choice itself as usual:
group.addEventListener("change", (event) => { const selected = (event.target as HTMLInputElement).value})<legend> is required even when it is hidden. Without it, someone listening to the page does not know what the three options choose between.
When this is not the one you want
Section titled “When this is not the one you want”| Situation | Component |
|---|---|
| One choice among three to five short options | Toggle Group |
| One choice among many, or long options | Radio in a Fieldset |
| Several choices at once | Checkbox |
| On and off for one setting | Switch |
| Actions, such as “bold, italic, underline” | Buttons with aria-pressed |
Classes you can style
Section titled “Classes you can style”| Class | What it is |
|---|---|
.lt-toggle-group | The group |
.lt-toggle-group__option | The label around each option |
| Variable | Default |
|---|---|
--lt-toggle-group-radius | var(--lt-spacing-1) |
--lt-toggle-group-height | var(--lt-spacing-10) |
--lt-toggle-group-padding | 0 var(--lt-spacing-4) |
The selected surface is set with :has(input:checked), that is from the state of the real radio button. There is no separate class to keep in sync.
See Customising for how the variables and the layer work.
Accessibility
Section titled “Accessibility”- The radio button is shrunk away, not removed.
display: nonewould take it out of the keyboard order, and the arrow keys would then stop working. - The arrow keys move between the options and select at the same time. Tab leaves the whole group. That is how radio buttons work, and it should not be overridden.
- The options have to be short. If the text gets long, it is really a list of radio buttons.
- Do not let a choice trigger something that cannot be undone. The user lands on every option on the way when moving with the arrow keys.