Skip to content

Inputs

Checkbox

Binary or indeterminate selection control with full keyboard support.

<script>
  import { Checkbox } from "@codeatlasdev/ui";
  let accepted = $state(false);
</script>

<Checkbox label="I accept the terms" bind:checked={accepted} />

A checkbox rendered without label (for example in a table row) needs an aria-label. Space toggles it. Any other native attribute or handler (data-*, id, onclick, onkeydown, aria-describedby, value…) is forwarded to the native <input>, and ref gives you that input.

#008

States

Unchecked, checked and indeterminate.

Reference #008 · Pick in the gallery

Code
svelte
<script lang="ts">
  import { Checkbox } from '@codeatlasdev/ui';

  let basic = $state(false);
  let checked = $state(true);
</script>

<Checkbox bind:checked={basic} label="Unchecked (click me)" />
<Checkbox bind:checked label="Pre-checked" />
<Checkbox indeterminate label="Indeterminate" />
#007

Disabled

Reference #007 · Pick in the gallery

Code
svelte
<script lang="ts">
  import { Checkbox } from '@codeatlasdev/ui';
</script>

<Checkbox disabled label="Disabled unchecked" />
<Checkbox checked disabled label="Disabled checked" />
<Checkbox indeterminate disabled label="Disabled indeterminate" />
#009

Without label

Bare checkbox for table rows or custom layouts.

Reference #009 · Pick in the gallery

Code
svelte
<script lang="ts">
  import { Checkbox } from '@codeatlasdev/ui';

  let value = $state(false);
</script>

<Checkbox bind:checked={value} aria-label="Unlabelled checkbox" />
<Checkbox checked aria-label="Unlabelled checked checkbox" />
<Checkbox indeterminate aria-label="Unlabelled indeterminate checkbox" />
#387

Shift range selection

onclick is forwarded to the input and runs just before onchange, so shiftKey is readable. data-testid reaches the input.

0 selected. Shift+click extends the range.

Reference #387 · Pick in the gallery

Code
svelte
<script lang="ts">
  import { Checkbox } from '@codeatlasdev/ui';

  const rows = ['Invoice 101', 'Invoice 102', 'Invoice 103', 'Invoice 104', 'Invoice 105'];
  let selected = $state<boolean[]>(rows.map(() => false));
  let anchor = -1;
  let shift = false;

  function toggle(index: number, on: boolean) {
    if (shift && anchor >= 0) {
      const [from, to] = anchor < index ? [anchor, index] : [index, anchor];
      for (let i = from; i <= to; i++) selected[i] = on;
    } else {
      selected[index] = on;
    }
    anchor = index;
  }
</script>

<ul class="list">
  {#each rows as row, i (row)}
    <li>
      <Checkbox
        label={row}
        checked={selected[i]}
        data-testid="row-{i}"
        onclick={(e) => (shift = e.shiftKey)}
        onchange={(on) => toggle(i, on)}
      />
    </li>
  {/each}
</ul>
<p class="out">{selected.filter(Boolean).length} selected. Shift+click extends the range.</p>

<style>
  .list {
    display: flex;
    flex-direction: column;
    gap: var(--ca-space-2);
    margin: 0;
    padding: 0;
    list-style: none;
  }

  .out {
    margin: var(--ca-space-3) 0 0;
    font-size: var(--ca-font-size-body2);
    color: var(--ca-text-secondary);
  }
</style>

Props

PropTypeDefaultDescription
checkedbooleanfalseBindable checked state.
indeterminatebooleanfalseRenders the mixed state.
disabledbooleanfalseDisables interaction.
namestring–Native name, so the checkbox is in FormData on a plain form submit (value `on` when checked, absent when not).
labelstring–Visible label rendered beside the checkbox.
aria-labelstring–Accessible name used when no visible label is rendered.
aria-labelledbystring–Id of an element that names the checkbox. Ignored when label is set.
classstring–Extra classes on the wrapper.
refHTMLInputElement | null–Bindable native input element.
onchange(checked: boolean, event: Event) => void–Called when the checked state changes, with the native change event.