ShardsUI is in beta. APIs may change before 1.0.

Checkbox Group

Checkboxes sharing one value.

Notify me about
<script lang="ts">
  import { Checkbox } from '@shardsui/svelte/checkbox'
  import { CheckboxGroup } from '@shardsui/svelte/checkbox-group'

  const id = $props.id()

  const topics = [
    { value: 'updates', label: 'Updates' },
    { value: 'mentions', label: 'Mentions' },
    { value: 'activity', label: 'Activity' }
  ]
</script>

<CheckboxGroup
  value={['activity']}
  class="flex flex-col items-start gap-2 text-gray-900"
  aria-labelledby={id}
>
  <div class="text-sm font-semibold" {id}>Notify me about</div>

  {#each topics as topic (topic.value)}
    <label class="flex items-center gap-2 text-sm font-normal">
      <Checkbox.Root
        name="topics"
        value={topic.value}
        class="flex size-4 shrink-0 items-center justify-center rounded-xs focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gray-950 data-checked:bg-gray-900 data-unchecked:border data-unchecked:border-gray-300"
      >
        <Checkbox.Indicator class="flex text-gray-50 data-unchecked:hidden">
          {@render checkIcon()}
        </Checkbox.Indicator>
      </Checkbox.Root>
      {topic.label}
    </label>
  {/each}
</CheckboxGroup>

{#snippet checkIcon()}
  <svg viewBox="0 0 24 24" fill="none" aria-hidden="true" class="size-4">
    <path
      d="M6 14.15L10.0321 18L18 7"
      stroke="currentColor"
      stroke-width="1.5"
      stroke-linecap="round"
      stroke-linejoin="round"
    />
  </svg>
{/snippet}

Anatomy

A Checkbox Group wraps a set of Checkbox parts. Import both and nest the checkboxes inside the group:

<script>
  import { Checkbox } from '@shardsui/svelte/checkbox'
  import { CheckboxGroup } from '@shardsui/svelte/checkbox-group'
</script>

<CheckboxGroup>
  <Checkbox.Root />
</CheckboxGroup>

Usage guidelines

  • Form controls must have an accessible name: name them with <label> elements, or with the Field and Fieldset components.

Examples

Labeling a checkbox group

Point the group at a sibling label with aria-labelledby:

<div id="protocols-label">Allowed network protocols</div>
<CheckboxGroup aria-labelledby="protocols-label">
  <!-- checkboxes -->
</CheckboxGroup>

For the individual checkboxes, the simplest option is to wrap each one in a <label>:

<label>
  <Checkbox.Root value="http" />
  HTTP
</label>

Rendering as a native button

Checkbox.Root renders a <span> by default so it can live inside a <label>. When each checkbox has its own label tied to it with for/id, render it as a native button with as="button":

<div id="protocols-label">Allowed network protocols</div>
<CheckboxGroup aria-labelledby="protocols-label">
  <div>
    <label for="protocol-http">HTTP</label>
    <Checkbox.Root id="protocol-http" value="http" as="button">
      <Checkbox.Indicator />
    </Checkbox.Root>
  </div>
</CheckboxGroup>

Form integration

Combine Field and Fieldset to label the group and hook it into a form:

<Field.Root name="allowedNetworkProtocols">
  <Fieldset.Root>
    <Fieldset.Legend>Allowed network protocols</Fieldset.Legend>
    <CheckboxGroup>
      <label>
        <Checkbox.Root value="http" />
        HTTP
      </label>
      <label>
        <Checkbox.Root value="https" />
        HTTPS
      </label>
      <label>
        <Checkbox.Root value="ssh" />
        SSH
      </label>
    </CheckboxGroup>
  </Fieldset.Root>
</Field.Root>

API reference

PropTypeDefault
AttributeDescription
data-disabledPresent when the group is disabled.
data-validPresent when the field is valid (when wrapped in Field.Root).
data-invalidPresent when the field is invalid (when wrapped in Field.Root).
data-touchedPresent when the field has been touched (when wrapped in Field.Root).
data-dirtyPresent when the value has changed from its initial value (when wrapped in Field.Root).
data-filledPresent when at least one checkbox is checked (when wrapped in Field.Root).
data-focusedPresent when the group is focused (when wrapped in Field.Root).