Selection
Checkbox
MD3 checkbox.
import { Checkbox } from 'omaris' Examples
Basic
A choice submitted with the form. The label is a prop wired to the control, so clicking the text toggles it too.
<script lang="ts"> import { Checkbox } from 'omaris'; let agreed = $state(false);</script><Checkbox label="Email me about outages" bind:checked={agreed} /> Description and states
indeterminate is the parent of a partly-checked set, not a third value.
<script lang="ts"> import { Checkbox } from 'omaris'; let email = $state<boolean>(true); let sms = $state<boolean>(false); const all = $derived(email && sms); const some = $derived((email || sms) && !all); function toggleAll() { const next = !all; email = next; sms = next; }</script><div class="flex flex-col gap-3"> <Checkbox label="Notifications" description="Two channels available" checked={all} indeterminate={some} onchange={toggleAll} /> <div class="flex flex-col gap-3 ps-7"> <Checkbox label="Email" bind:checked={email} /> <Checkbox label="SMS" bind:checked={sms} /> </div> <Checkbox label="Disabled" disabled /> <Checkbox label="Invalid" invalid description="You have to accept the terms." /></div> Tones and sizes
Any colour role — success for a consent, destructive for a dangerous opt-in — and lg where a thumb needs the room.
<script lang="ts"> import { Checkbox } from 'omaris';</script><Checkbox label="primary" checked /><Checkbox label="success" tone="success" checked /><Checkbox label="destructive" tone="destructive" checked /><Checkbox label="Large" size="lg" checked /> Drag to paint
Press one box and drag down the column: every box the pointer crosses lands on the state the first one was heading to. On a touch screen, hold for a moment first so a scroll stays a scroll.
2 of 8 connected
<script lang="ts"> import { Checkbox, Text } from 'omaris'; const services = ['Vercel', 'Linear', 'GitHub', 'Figma', 'Stripe', 'Notion', 'Dropbox', 'Asana']; let connected = $state<string[]>(['GitHub', 'Figma']); function toggle(service: string) { connected = connected.includes(service) ? connected.filter((entry) => entry !== service) : [...connected, service]; }</script><div class="w-full max-w-xs"> <ul class="divide-y divide-border overflow-hidden rounded-lg border border-border"> {#each services as service (service)} {@const on = connected.includes(service)} <li class="flex items-center gap-2 px-2 transition-colors duration-150 ease-standard motion-reduce:transition-none" class:bg-primary-container={on} > <Checkbox label={service} checked={on} onchange={() => toggle(service)} /> </li> {/each} </ul> <Text variant="body-sm" class="mt-2 text-muted-foreground"> {connected.length} of {services.length} connected </Text></div> When to use it
Use it for
- Any number of items from a set: permissions, columns to show, rows to act on.
- A yes/no submitted with the form rather than applied at once: "Accept the terms", "Send me the digest". Bind
checkedand give it aname. - The parent row over a set.
indeterminatewhile some but not all children are checked. The parent computes it; it is not a third value. - An option that needs explaining.
descriptionis the second line that says what the first commits you to. - A run of rows ticked in one go. Dragging across a column of checkboxes paints them all to the state the first one was heading to, the way a phone's photo grid selects. It is on by default and needs no wiring.
Not for
- A setting that takes effect the moment it flips → Switch.
- Exactly one of several → Radio.
- A filter above a list that shows its result as you tick → filter Chips.
- A single boolean in a toolbar → a
toggleIcon Button. - More than about seven options → a searchable Combobox.
Do
- Use
label(orchildrenfor rich text) rather than a separate<label>. The text is wired to the input, so clicking it toggles the box. - Keep
size="md", the 40dp target, anywhere a thumb will land.smis for a dense table cell. - Mark a required-but-empty box
invalidand say why in text beside it. The red border is not an error message. - Compute the parent's
indeterminatefrom the children and let a click on the dash check everything. - Keep a list of checkboxes in one container — a
ul, aform, atable— so a paint stroke knows where it ends. Across containers you don't control, give every box in the run the samepaint="name".
Don't
- Phrase the label as a negative. "Don't email me" makes a tick mean no.
- Use a column of checkboxes as a settings list. That list is Switch rows.
- Restyle the box through
classesuntil the empty state has no border. An unchecked box must still be visible. - Turn
paintoff because a row does something on change. If ticking a box fires a request, the fix is batching the result, not making people press twelve times.
Quick reference
tone primary(default)secondarytertiarydestructivesuccesswarninginfo
size md(default)lg
API
Checkbox
MD3 checkbox.
A real <input type="checkbox"> does the work — keyboard, form submission, indeterminate — and is drawn over with a box that fills from the center when checked. The 40dp state layer around the 18dp box is the MD3 touch target; it only shows on hover, focus and press.
import { Checkbox } from 'omaris' Parts
Every element this renders is reachable from outside. Pass Tailwind for one part as classes={{ part: '…' }}; class covers the root and is merged last, so it always wins.
root- No description in the source yet.
control- Wrapper that holds the state layer and the box.
box- The visible square: the outline, and nothing else.
fill- The colour, on a layer of its own so it can grow from the middle rather than snap on. Scaling a solid square is one compositor property — it stays at 60fps in a list of a hundred rows, which animating
background-colorwould not. input- The
<input>itself: invisible, but still the thing you click. mark- The tick / dash. Both paths are always in the DOM and are drawn on by walking
stroke-dashoffsetdown to zero, so the tick writes itself in the direction a hand would and the dash slides out from the centre — a mounted{#if}could only fade. label- No description in the source yet.
description- No description in the source yet.
Props
tone Defaults to 'primary'
CheckboxTone primarysecondarytertiarydestructivesuccesswarninginfo
size Defaults to 'md'
CheckboxSize mdlg
checked bindableDefaults to false
boolean Bindable.
indeterminate Defaults to false
boolean The dash state — some but not all children are checked.
label string Text beside the box.
description string Second line under the label.
invalid boolean Inside a Field, defaults to the field's.
haptics Defaults to true
boolean A haptic tap when it's ticked or cleared. Follows the shared haptics store; false opts this checkbox out.
sound Defaults to true
boolean A sound cue when it's ticked. Follows the shared sound store; false opts this checkbox out.
paint Defaults to true
boolean | string Drag across a run of checkboxes to set them all, the way a phone's photo grid selects. The box you press decides the direction — start on an empty one and the stroke ticks, start on a ticked one and it clears. On by default.
A stroke stays inside its container (the nearest list, form, table or fieldset); pass a name to paint across one you don't control, and the same name has to be on every box in the run. false opts a checkbox out of being painted and of starting a stroke.
class string classes CheckboxClasses Per-part Tailwind overrides. class still covers the root.
children Snippet Rich label, in place of label.
ref bindableDefaults to null
HTMLInputElement | null