Checkbox
A tri-look checkbox — unchecked, checked, indeterminate and disabled — built on a native checkbox input
Preview
<script lang="ts">
import { Checkbox } from "fancy-ui-svelte";
let agreed = $state(false);
</script>
<Checkbox bind:checked={agreed}>I agree to the terms and conditions</Checkbox>Installation
Usage
<script lang="ts">
import { Checkbox } from 'fancy-ui-svelte';
</script>
<Checkbox />Examples
Basic Usage
A single checkbox with a bound checked state.
<script lang="ts">
import { Checkbox } from "$lib/fancy-ui/checkbox";
let agreed = $state(false);
</script>
<Checkbox bind:checked={agreed}>I agree to the terms and conditions</Checkbox>States
Unchecked, checked, indeterminate and disabled, side by side.
<script lang="ts">
import { Checkbox } from "$lib/fancy-ui/checkbox";
</script>
<div class="flex flex-col gap-3">
<Checkbox checked={false}>Unchecked</Checkbox>
<Checkbox checked={true}>Checked</Checkbox>
<Checkbox checked={false} indeterminate={true}>Indeterminate</Checkbox>
<Checkbox checked={false} disabled>Disabled</Checkbox>
</div>Indeterminate
A parent checkbox reflecting a mixed selection of children.
<script lang="ts">
import { Checkbox } from "$lib/fancy-ui/checkbox";
let items = $state([
{ label: "Design", done: true },
{ label: "Build", done: false },
{ label: "Ship", done: false },
]);
const allDone = $derived(items.every((item) => item.done));
const noneDone = $derived(items.every((item) => !item.done));
function setAll(checked: boolean) {
items = items.map((item) => ({ ...item, done: checked }));
}
</script>
<div class="flex flex-col gap-3">
<Checkbox checked={allDone} indeterminate={!allDone && !noneDone} onCheckedChange={setAll}>
Select all
</Checkbox>
<div class="border-border ml-[10px] flex flex-col gap-2 border-l pl-4">
{#each items as item, index (item.label)}
<Checkbox
checked={item.done}
onCheckedChange={(checked) => (items[index] = { ...item, done: checked })}
>
{item.label}
</Checkbox>
{/each}
</div>
</div>With FormField
Wrapped in FormField — no id or invalid prop needed on Checkbox itself.
<script lang="ts">
// FormField renders its own internal Label from the `label` prop below and
// derives invalid state from whether `error` is set — it supplies
// controlId, aria-describedby and aria-invalid to Checkbox through
// context, so Checkbox itself needs no id or invalid prop here. The
// FormField's `label` ("Terms") is a group heading; Checkbox's own
// children ("I agree...") is still the control's own accessible label —
// the two serve different purposes.
import { FormField } from "$lib/fancy-ui/form-field";
import { Checkbox } from "$lib/fancy-ui/checkbox";
let agreed = $state(false);
</script>
<FormField
label="Terms"
required
error={agreed ? undefined : "You must agree before continuing."}
class="w-full max-w-sm"
>
<Checkbox bind:checked={agreed}>I agree to the terms and conditions</Checkbox>
</FormField>Props
| Prop | Type | Default | Description |
|---|---|---|---|
checked | boolean | false | Whether the box is checked; bindable |
indeterminate | boolean | false | Mixed/dash visual state; bindable |
onCheckedChange | (checked: boolean) => void | - | Called with the new checked value whenever the box is activated |
disabled | boolean | false | Blocks interaction; excluded from form submission |
required | boolean | false | Native required |
invalid | boolean | false | Drives the error border and aria-invalid |
id | string | - | Element id |
name | string | - | Native name, read on form submission |
value | string | - | Form value submitted while checked |
label | string | - | Accessible name, rendered as aria-label; skip it when children already supplies the visible label text |
class | string | - | Additional CSS classes, merged onto the wrapping label |
ref | HTMLInputElement | null | null | Bindable element reference to the native input |
sound | boolean | false | Plays toggle-on or toggle-off on each change, once the user has enabled sound |
Slots
| Slot | Description |
|---|---|
children | Visible label text, rendered beside the box |
Links
Related components
Autocomplete
A free-text field with a portalled panel of matching suggestions — any typed value is valid; the panel only ever helps finish it faster.
Combobox
A single-choice text field over a closed set of options — typing filters a portalled listbox, and a value outside the list can never be selected.
DatePicker
A field that opens a floating month grid, with full keyboard navigation (arrow keys across days, Page Up/Down across months, Shift for years), min/max and per-day disabling, and a fully localized accessible name on every day cell.