Checkbox
Plain CSS on an ordinary <input type="checkbox">, so the keyboard, FormData and the browser’s own validation work as before. If the user should choose one of several options, Radio is right. If the choice turns a setting on or off and takes effect at once, use Switch.
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/checkbox/checkbox.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.36.0/src/components/css/label/label.css"><!-- Or everything in one file: https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.36.0/dist/lotek.css --><div class="lt-checkbox-row"><input class="lt-checkbox" type="checkbox" id="terms" /><label class="lt-label" for="terms">I accept the terms</label></div>
<div class="lt-checkbox-row"><input class="lt-checkbox" type="checkbox" id="newsletter" checked /><label class="lt-label" for="newsletter">Send me newsletters</label></div>
<div class="lt-checkbox-row"><input class="lt-checkbox" type="checkbox" id="confirm" data-state="invalid" aria-invalid="true" /><label class="lt-label" for="confirm">I confirm that the information is correct</label></div>
<div class="lt-checkbox-row"><input class="lt-checkbox" type="checkbox" id="archived" checked disabled /><label class="lt-label" for="archived">The case is archived</label></div>import "@lo-tek/interfaces/tokens.css"import "@lo-tek/interfaces/checkbox.css"import "@lo-tek/interfaces/label.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, you spread the attributes in. That is the route in React, Astro and anything else that renders:
import { lt } from "@lo-tek/interfaces/react"
<div className={lt.checkbox.row}> <input {...lt.checkbox()} id="terms" /> <label {...lt.label()} htmlFor="terms">I accept the terms</label></div>The import goes to /react here, since the block is JSX. From there the keys are called className and htmlFor. In Astro and anything else without React you import @lo-tek/interfaces and get class and for.
If the element is already there, you set them on it. That is the route when you enhance HTML a server or a template has sent:
import { lt, type FieldState } from "@lo-tek/interfaces"
const box = document.querySelector<HTMLInputElement>("#confirm")if (!box) throw new Error("element not found")
box.addEventListener("change", () => { const state: FieldState = box.checked ? "default" : "invalid"
lt.setAttributes(box, lt.checkbox({ state }))})lt.checkbox() sets type for you, so the box cannot become a text field with the checkbox’s style. lt.checkbox.row gives the class for the row around it. See Type-safe use.
data-state | Used for |
|---|---|
| (omitted) | Normal state |
invalid | Validation has failed |
success | The choice is confirmed valid. Use sparingly. |
data-state is colour. Screen readers also need aria-invalid="true". lt.checkbox({ state: "invalid" }) and Field both set it.
Partly checked
Section titled “Partly checked”“Select all” is neither on nor off when some of the options under it are checked. That state exists only as a property in JavaScript, not as an HTML attribute:
<div class="lt-checkbox-row"> <input class="lt-checkbox" type="checkbox" id="all" /> <label class="lt-label" for="all">Select all attachments</label></div><div class="lt-checkbox-row"> <input class="lt-checkbox attachment" type="checkbox" id="attachment-certificate" name="attachment" value="certificate" checked /> <label class="lt-label" for="attachment-certificate">Birth certificate</label></div><div class="lt-checkbox-row"> <input class="lt-checkbox attachment" type="checkbox" id="attachment-lease" name="attachment" value="lease" /> <label class="lt-label" for="attachment-lease">Tenancy agreement</label></div>
<script type="module"> const all = document.getElementById("all") const options = document.querySelectorAll(".attachment")
function update() { const count = [...options].filter((box) => box.checked).length
all.checked = count === options.length all.indeterminate = count > 0 && count < options.length }
// "Select all" checks or unchecks everything under it. all.addEventListener("change", () => { for (const box of options) box.checked = all.checked update() }) for (const box of options) box.addEventListener("change", update) update()</script>Screen readers announce the state as “partially checked” by themselves. You do not need aria-checked="mixed" on a real <input>.
Several choices that belong together
Section titled “Several choices that belong together”If the boxes belong to the same question, group them in a Fieldset. The question is then announced before each option.
<fieldset class="lt-fieldset"><legend class="lt-legend">How would you like to be notified?</legend>
<div class="lt-checkbox-row"> <input class="lt-checkbox" type="checkbox" id="notify-email" name="notify" value="email" checked /> <label class="lt-label" for="notify-email">Email</label></div>
<div class="lt-checkbox-row"> <input class="lt-checkbox" type="checkbox" id="notify-sms" name="notify" value="sms" /> <label class="lt-label" for="notify-sms">Text message</label></div></fieldset>Identical name values give one key with several values in FormData. Read them with formData.getAll("notify").
Classes you can style
Section titled “Classes you can style”| Class | What it is |
|---|---|
.lt-checkbox | The box itself |
.lt-checkbox-row | The row that holds the box and the text side by side |
| Variable | Default |
|---|---|
--lt-checkbox-size | var(--lt-spacing-5) |
--lt-checkbox-radius | var(--lt-spacing-1) |
The tick and the dash are drawn from --lt-icon-check and --lt-icon-dash, which follow the theme. See Customising.
Accessibility
Section titled “Accessibility”- Every box needs a
<label>withfor. Without it the click area is only the box itself, and the screen reader reads nothing. - The text should say what happens when the box is checked, not what the question was called. “Send me newsletters”, not “Newsletter”.
- Do not submit the form or navigate when a box changes. The user expects to be able to check several before anything happens.
- If checking is required, set
requiredon the box. The browser then stops the submission itself.