Checkbox
BetaA box that is checked, unchecked or mixed, and submits with forms.
---
import Checkbox from "@/components/ui/checkbox/Checkbox.astro";
---
<Checkbox checked>Remember me on this device</Checkbox>Installation
npx eris-ui@latest add checkboxpnpm dlx eris-ui@latest add checkboxbunx eris-ui@latest add checkboxyarn dlx eris-ui@latest add checkboxInstalls @zag-js/checkbox, @zag-js/vanilla.
How it works
The checkbox is a real <input type="checkbox"> inside a <label>, drawn with CSS. It toggles, shows its state and submits with a form before its script loads, and with JavaScript turned off. The script adds the mixed state and data-state, data-focus and data-hover attributes for styling.
States
---
import Checkbox from "@/components/ui/checkbox/Checkbox.astro";
---
<div class="flex flex-col items-start gap-4">
<Checkbox indeterminate>Mixed</Checkbox>
<Checkbox disabled>Disabled</Checkbox>
<Checkbox disabled checked>
Disabled and checked
</Checkbox>
<Checkbox readOnly checked>
Read only
</Checkbox>
<Checkbox invalid>Invalid</Checkbox>
</div>A readOnly checkbox keeps focus and is still sent with the form, but does not change. A disabled checkbox is skipped by Tab and left out of the form.
In a form
Give the checkbox a name. While it is checked, the form sends that name with value, which defaults to on. While it is unchecked, the form sends nothing for it. A form reset returns it to how it loaded.
---
import Checkbox from "@/components/ui/checkbox/Checkbox.astro";
import Button from "@/components/ui/button/Button.astro";
---
<form class="flex flex-col items-start gap-4">
<Checkbox name="terms" value="accepted" required>
I accept the terms
</Checkbox>
<Checkbox name="newsletter">Send me the newsletter</Checkbox>
<div class="flex gap-3">
<Button type="submit" size="sm">
Sign up
</Button>
<Button type="reset" size="sm" variant="secondary">
Reset
</Button>
</div>
</form>Mixed state and select all
indeterminate starts a checkbox in the mixed state, shown as a dash. Clicking a mixed checkbox checks it.
To change the state from your own script, import setChecked from the component’s checkbox.ts and pass it the checkbox root and true, false or "indeterminate". It is safe to call before the checkbox has mounted.
setChecked fires no change event, the same as setting input.checked yourself. So a change event on the input always means the user did it.
---
import Checkbox from "@/components/ui/checkbox/Checkbox.astro";
---
<div class="flex flex-col items-start gap-3">
<Checkbox id="demo-all">All notifications</Checkbox>
<div id="demo-kinds" class="flex flex-col items-start gap-3 pl-8">
<Checkbox checked>Comments</Checkbox>
<Checkbox>Mentions</Checkbox>
<Checkbox>Invites</Checkbox>
</div>
</div>
<script>
import { setChecked } from "@/components/ui/checkbox/checkbox";
document.addEventListener("astro:page-load", () => {
const all = document.querySelector<HTMLElement>('[data-eris-id="demo-all"]');
const boxes = [...document.querySelectorAll<HTMLInputElement>("#demo-kinds input")];
if (!all || !boxes.length) return;
// Children changed: the parent becomes checked, unchecked or mixed.
const sync = () => {
const count = boxes.filter((box) => box.checked).length;
setChecked(all, count === 0 ? false : count === boxes.length ? true : "indeterminate");
};
boxes.forEach((box) => box.addEventListener("change", sync));
// Parent changed: every child follows it.
all.querySelector("input")!.addEventListener("change", (event) => {
const { checked } = event.target as HTMLInputElement;
boxes.forEach((box) => setChecked(box.closest<HTMLElement>("[data-eris]")!, checked));
});
sync();
});
</script>Without visible text
When a checkbox has no text next to it, as in a table row, name it with label so screen readers can announce it.
---
import Checkbox from "@/components/ui/checkbox/Checkbox.astro";
---
<Checkbox label="Select row" />Keyboard
| Key | Does |
|---|---|
| Tab | Moves focus to the checkbox |
| Space | Checks or unchecks the checkbox |
Props
| Prop | Default | Does |
|---|---|---|
checked |
false |
Checked when the page loads |
indeterminate |
false |
Starts in the mixed state |
name |
none | Field name sent with the form |
value |
"on" |
Value sent while the checkbox is checked |
disabled |
false |
Cannot be focused or changed, and is not submitted |
read |
false |
Can be focused and is submitted, but cannot be changed |
required |
false |
The form will not submit while the box is unchecked |
invalid |
false |
Marks the checkbox as failing validation |
form |
none | Id of a form elsewhere on the page |
label |
none | Accessible name when there is no visible text |
id |
random | Id for the instance, used to build the part ids |