Radio
Radioは、複数の選択肢の中から、1つだけを選択する際に使用されるコンポーネントです。
<script lang="ts">
import Label from '$lib/components/ui/atoms/Label.svelte';
import Radio from '$lib/components/ui/atoms/Radio.svelte';
</script>
<Label class="gap-2 group cursor-pointer">
<Radio /> 選択肢
</Label>
プロパティ
Radioは、以下のプロパティをサポートしています。
| 名前 | 型 | デフォルト値 | 説明 |
|---|---|---|---|
isError |
boolean |
false |
エラー状態を表現できます。 |
disabled |
boolean |
false |
入力を無効化します。操作できません。 |
インストールの手順
以下のコンポーネントのコードを、使いたいプロジェクトにコピー&ペーストします。
パスは実際のプロジェクトの構成にあわせて更新します。
atoms/Radio.svelte
<!--
@component
## 概要
- inputタグ radio のように、クリックなどのユーザー操作に対応する汎用的なボタンコンポーネントです
## 機能
- groupバインディングによる選択状態を共有します
- 見た目を変更するためのいくつかのスタイル用Propsが追加されています(詳細はPropsセクションを参照)
## Props
- isError: true の場合エラー時のスタイルを適用します
- disabled: 指定するとグレーアウトされ、クリック不可になります
## Usage
```svelte
<Radio name="radio_name" value="radio_value" />
```
-->
<script module lang="ts">
import type { ClassValue, HTMLInputAttributes } from 'svelte/elements';
import { cva, type VariantProps } from 'class-variance-authority';
export const radioBorderVariants = cva('size-4 border border-base-stroke-default rounded-full outline-primary 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: ['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 radioCircleVariants = cva('absolute inset-[0.1875rem] size-2.5 rounded-full scale-0 peer-checked:pointer-events-none peer-checked:scale-100', {
variants: {
/** 操作できるかどうか */
disabled: {
true: ['opacity-50 pointer-events-none'],
false: ['cursor-pointer'],
},
/** エラーかどうか */
isError: {
true: ['bg-destructive'],
false: ['bg-primary'],
},
},
});
export type RadioVariants = VariantProps<typeof radioCircleVariants>;
export interface RadioProps extends RadioVariants, HTMLInputAttributes {
/** グループ */
group?: any;
/** 値 */
value?: any;
/** クラス */
class?: ClassValue;
}
</script>
<script lang="ts">
let { group = $bindable(), isError = false, disabled = false, class: className, ...inputAttributes }: RadioProps = $props();
let radioBorderVariantClass = $derived(radioBorderVariants({ disabled, isError }));
let radioCircleVariantClass = $derived(radioCircleVariants({ disabled, isError }));
</script>
<label class={[className, 'relative block size-fit']}>
<input class="sr-only peer" type="radio" bind:group {disabled} {...inputAttributes} />
<div class={radioBorderVariantClass}></div>
<div class={radioCircleVariantClass}></div>
</label>
使い方
<script lang="ts">
import Label from '$lib/components/ui/atoms/Label.svelte';
import Radio from '$lib/components/ui/atoms/Radio.svelte';
</script>
<Label class="gap-2 group cursor-pointer">
<Radio /> 選択肢
</Label>
サンプル
Default
特に操作が行われていない、デフォルトの状態です。
<script lang="ts">
import Label from '$lib/components/ui/atoms/Label.svelte';
import Radio from '$lib/components/ui/atoms/Radio.svelte';
</script>
<Label class="gap-2 group cursor-pointer">
<Radio /> 選択肢
</Label>
Error
入力内容に問題があり、エラーが表示されている状態です。
<script lang="ts">
import Label from '$lib/components/ui/atoms/Label.svelte';
import Radio from '$lib/components/ui/atoms/Radio.svelte';
</script>
<Label class="gap-2 group cursor-pointer">
<Radio isError /> 選択肢
</Label>
Disabled
利用不可の状態です。
<script lang="ts">
import Label from '$lib/components/ui/atoms/Label.svelte';
import Radio from '$lib/components/ui/atoms/Radio.svelte';
</script>
<Label class="gap-2 group cursor-pointer" disabled>
<Radio disabled /> 選択肢
</Label>
Group
bind:groupを使うことで、複数のラジオボタンをグループ化し、同じ値を共有できます。
<script lang="ts">
import DebugConsole from '$lib/components/ui/atoms/DebugConsole.svelte';
import Label from '$lib/components/ui/atoms/Label.svelte';
import Radio from '$lib/components/ui/atoms/Radio.svelte';
let group = $state('item1');
</script>
<div class="w-full">
<div class="grid gap-2">
<Label class="gap-2 group cursor-pointer">
<Radio name="radio_name" value="item1" bind:group /> 選択肢1
</Label>
<Label class="gap-2 group cursor-pointer">
<Radio name="radio_name" value="item2" bind:group /> 選択肢2
</Label>
<Label class="gap-2 group cursor-pointer">
<Radio name="radio_name" value="item3" bind:group /> 選択肢3
</Label>
</div>
<DebugConsole class="mt-4" data={{ group }} />
</div>