Checkbox

Checkboxは、ユーザーが複数の選択肢から1つ以上を選択できるコンポーネントです。

プロパティ

Checkboxは、以下のプロパティをサポートしています。

名前 デフォルト値 説明
checked boolean チェック状態を制御します。
indeterminate boolean false 一部のみ選択された状態や、不確定な状態を表します。
isError boolean false エラーのスタイルを適用します。
disabled boolean false チェックボックスを無効化します。

インストールの手順

以下のコンポーネントのコードを、使いたいプロジェクトにコピー&ペーストします。
パスは実際のプロジェクトの構成にあわせて更新します。

atoms/Checkbox.svelte
        <!--
@component
## 概要
- ユーザーが複数の選択肢から1つ以上を選択できるコンポーネントです

## 機能
- checkboxタグと同様に bind:group が使用できます
- 見た目を変更するためのいくつかのスタイル用Propsが追加されています(詳細はPropsセクションを参照)

## Props
- isError: true の場合エラー時のスタイルを適用します
- disabled: 指定するとグレーアウトされ、クリック不可になります
- indeterminate: 一部のみ選択された状態や、不確定な状態です

## Usage
```svelte
<Checkbox bind:checked />
```
-->

<script module lang="ts">
  import type { ClassValue, HTMLInputAttributes } from 'svelte/elements';
  import { cva, type VariantProps } from 'class-variance-authority';

  export const checkboxBorderVariants = cva('relative size-4 border border-base-stroke-default rounded-xs outline-primary/20 transition-shadow peer-focus-visible:hover:outline-[0.125rem] peer-focus-visible:outline-[0.125rem] peer-focus-visible:outline-offset-[0.125rem] peer-focus-visible:hover:outline-primary peer-focus-visible:outline-primary peer-focus-visible:hover:ring-[0.125rem] peer-focus-visible:hover:ring-primary/20', {
    variants: {
      /** 操作できるかどうか */
      disabled: {
        true: ['bg-base-container-muted opacity-50 pointer-events-none'],
        false: ['cursor-pointer group-hover:ring-[0.25rem] hover:ring-[0.25rem] group-hover:ring-primary/20 hover:ring-primary/20'],
      },
      /** エラーかどうか */
      isError: {
        true: ['border-destructive'],
        false: [],
      },
    },
  });

  export const checkboxIconVariants = cva('absolute top-0 size-4 rounded-xs text-base-foreground-on-fill-bright pointer-events-none scale-0 transition-shadow peer-checked:scale-100', {
    variants: {
      /** 操作できるかどうか */
      disabled: {
        true: ['bg-base-container-muted opacity-50'],
        false: [],
      },
      /** エラーかどうか */
      isError: {
        true: ['bg-destructive'],
        false: ['bg-primary'],
      },
    },
  });

  export type CheckboxVariants = VariantProps<typeof checkboxBorderVariants>;

  export interface CheckboxProps extends CheckboxVariants, HTMLInputAttributes {
    /** クラス */
    class?: ClassValue;
    /** チェックしているかどうか */
    checked?: boolean;
    /** グループ */
    group?: any[];
    /** 値 */
    value?: any;
    /** 不確定な要素かどうか */
    indeterminate?: boolean;
  }

  // for bind:group
  const groupSetMap = new WeakMap<any[], Set<any>>();

  function getGroupSet(group: any[]): Set<any> {
    let set = groupSetMap.get(group);
    if (!set) {
      set = new Set(group);
      groupSetMap.set(group, set);
    }
    return set;
  }
</script>

<script lang="ts">
  import { Check, Minus } from '@lucide/svelte';
  import { untrack } from 'svelte';

  let { class: className, checked = $bindable(false), group = $bindable(), indeterminate = false, isError = false, disabled = false, value, ...inputAttributes }: CheckboxProps = $props();

  let checkboxBorderVariantClass = $derived(checkboxBorderVariants({ disabled, isError }));

  let checkboxIconVariantClass = $derived(checkboxIconVariants({ disabled, isError }));

  $effect(() => {
    if (group) {
      const set = getGroupSet(group);
      checked = set.has(value);
    }
  });

  $effect(() => {
    // watch `checked`
    checked;
    untrack(() => {
      if (group) {
        const set = getGroupSet(group);

        // skip
        if (set.has(value) === checked) return;

        if (checked) {
          set.add(value);
        }
        else {
          set.delete(value);
        }

        // update group
        group = [...set.values()];
      }
    });
  });
</script>

<label class={[className, 'relative block size-fit']}>
  <input class="sr-only peer" type="checkbox" {disabled} {...inputAttributes} bind:checked />
  <div class={checkboxBorderVariantClass}></div>
  {#if indeterminate}
    <Minus class={checkboxIconVariantClass} />
  {:else}
    <Check class={checkboxIconVariantClass} />
  {/if}
</label>

      

使い方

サンプル

Default

特に操作が行われていない、デフォルトの状態です。

Error

入力内容に問題があり、エラーが表示されている状態です。

Disabled

利用不可の状態です。

Indeterminate

一部のみ選択された状態や、不確定な状態を示します。
ツリービューで親が一部の子だけ選ばれている場合などに使用されます。

Group

bind:groupを使うことで、複数のチェックボックスをグループ化し、同じ値を共有できます。
これにより、複数のチェックボックスの状態を一括で管理できます。