Checkbox
A native checkbox with a custom look. Toggle a single option, or one item in a multi-select list.
Last updated
Show codeHide code
<Checkbox label="Email me about product updates" />Add
npx @ava-ui/apogee add checkbox
No Apogee dependencies.
Usage
---
import Checkbox from '@/components/apogee/Checkbox/Checkbox.astro'
<JsNote fallback="The box renders unchecked; everything else is the native control.">
Sets the `indeterminate` DOM property on checkboxes rendered with `indeterminate` (it has no HTML attribute).
</JsNote>
---
<Checkbox label="Accept terms and conditions" name="terms" />
API
@composable — exposed to Content Editors in AVA. Every prop other than
id, label, and class passes straight through to the underlying
<input type="checkbox"> (the Props interface has an open index signature,
so checked, disabled, required, name, value, aria-*, etc. are all
valid and unchecked by the type system).
| Prop | Type | Default | Description |
|---|---|---|---|
id |
string |
auto-generated (apogee-<random>) |
Id on the <input>, and for on the <label>. Set your own if you need a stable id (e.g. to target it from a <label for> elsewhere). |
label |
string |
— | Visible label text, rendered in a real <label>. Omit to render the checkbox alone (then supply your own aria-label). |
size |
'small' | 'medium' | 'large' |
'medium' |
Control and label size. |
hasError |
boolean |
false |
Marks the control invalid (aria-invalid, critical border). |
hint |
string |
— | Supporting text under the label; the input lists it in aria-describedby. The label turns medium weight to read as a heading. |
indeterminate |
boolean |
false |
Mixed state (some children checked): a dash instead of a tick, set by a small island; clears on the first change. |
class |
string |
— | Extra classes on the wrapping <div>, appended last. |
...rest |
any |
— | Passed straight to the <input> — e.g. checked, disabled, required, name, value. |
Hint
Show codeHide code
<Checkbox label="Email me" hint="Product news, once a month." />Indeterminate and slot label
Show codeHide code
<Checkbox indeterminate label="Select all" />
<Checkbox><span>Accept the <a href="#" class="text-primary underline">terms</a></span></Checkbox>Sizes
Show codeHide code
<Checkbox name="size-small" label="Small" size="small" />
<Checkbox name="size-medium" label="Medium" size="medium" />
<Checkbox name="size-large" label="Large" size="large" />States
The real <input> is styled directly (appearance: none) — it stays the
actual control, so every state below is native, not simulated:
- Unchecked — bordered box,
--border-neutral. - Hover (unchecked, enabled) — border darkens to
--foreground-neutral-faded. - Checked — filled
--background-primarywith an inline checkmark icon. - Indeterminate — filled
--background-primarywith a dash icon. This is a DOM property, not an HTML attribute (el.indeterminate = true), so it can only be set via script — it can’t be demonstrated in a static<Preview>here. - Focus — visible
focus-visiblering,--border-primary. - Disabled — disabled fill, border and label colour,
not-allowedcursor.
Show codeHide code
<Checkbox label="Unchecked" />
<Checkbox label="Checked" checked />
<Checkbox label="Disabled" disabled />
<Checkbox label="Checked and disabled" checked disabled />Examples
Without a visible label (icon-only context — always add an aria-label):
Show codeHide code
<Checkbox aria-label="Select row" />As part of a form, with name and value:
<form>
<Checkbox name="newsletter" value="yes" label="Subscribe to the newsletter" />
</form>
Setting indeterminate from script (list “select all” pattern):
<script>
document.querySelector('#select-all').indeterminate = true
</script>
Accessibility
- Real
<input type="checkbox">— full keyboard support, correct AT announcement, and native form participation for free. No JS, no fake proxy element. - Keyboard —
Tabto focus,Spaceto toggle. - Pass
labelfor a proper<label for>association; if you omit it, provide your ownaria-label(see the icon-only example above). - Focus ring is always visible on keyboard focus (
focus-visible, not:focus). - Native semantics — no extra ARIA needed beyond a label.
Tokens
The tick and dash are a CSS mask filled with --on-primary, so they follow the theme and the brand.
| Token | Used for |
|---|---|
--border-neutral |
Unchecked border |
--background-page |
Unchecked fill |
--foreground-neutral-faded |
Hover border (unchecked, enabled) |
--background-primary |
Checked / indeterminate fill and border |
--outline-color-focus |
Focus ring |
Do / Don’t
- Do always pair the checkbox with a
label(oraria-label) — never leave it unlabeled. - Do use
indeterminateonly for a “select all” control that spans a partially-selected set. - Don’t use a Checkbox for a single on/off setting that takes effect immediately — use
Switch. - Don’t disable a checked checkbox to communicate “this is locked” without also explaining why nearby — disabled alone reads as broken to some users.
Content
- Label states the setting being toggled, not a question (“Email me updates”, not “Do you want emails?”).
- Sentence case, no ending period, ideally one line.