# Radio Group

Single-select radio group with bindable value and per-item label/description.

- Package: `@mielui/svelte`
- Component version: `1.0.1`
- Depends on Mielui components: _internal/utils
- Shared utilities: utils.cn, utils.createContext, utils.pressable

## Install

~~~~sh
pnpm dlx @mielui/svelte add radio-group
~~~~

## API

This reference is generated at build time from the component manifest, public `index.ts`, and documentation examples below. Changes to those source files are reflected here in the published Markdown. Standard Svelte and HTML attributes accepted by the exported prop types are supported.


### Item

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |
| value | string | - | Yes | No | Value this option selects. |
| disabled | boolean \| undefined | - | No | No | Prevents interaction and dims the control. |
| label | string \| undefined | - | No | No | Visible label linked to the control. |
| description | string \| undefined | - | No | No | Supporting text under the label, announced with the control. |
| id | string \| undefined | - | No | No | Id of the element. |
| class | (string & (ClassValue \| null)) \| undefined | - | No | No | Classes added to the element. |
| children | Snippet<[]> \| undefined | - | No | No | Content rendered inside. |

Also accepts the native HTML attributes and events listed in the rendered API reference.

### Root

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |
| value | string \| undefined | - | No | Yes | Selected value. Bindable. |
| name | string \| undefined | - | No | No | Field name submitted with the form. |
| disabled | boolean \| undefined | false | No | No | Prevents interaction and dims the control. |
| onValueChange | ((value: string) => void) \| undefined | - | No | No | Called with the new value when it changes. |
| aria-label | string \| undefined | - | No | No | Accessible name when there is no visible label. |
| aria-labelledby | string \| undefined | - | No | No | Id of the element that labels it. |
| children | Snippet<[]> \| undefined | - | No | No | Content rendered inside. |
| class | string \| undefined | - | No | No | Classes added to the element. |



### Public types

~~~~ts
import type { DefaultProps } from '@mielui/svelte/utils';
import type { Snippet } from 'svelte';
import type { HTMLInputAttributes } from 'svelte/elements';
import Root from './radio-group.svelte';
import Item from './radio-group-item.svelte';

export type RadioGroupProps = {
    /** Selected value. Bindable. */
    value?: string;
    /** Field name submitted with the form. */
    name?: string;
    /** Prevents interaction and dims the control. */
    disabled?: boolean;
    /** Called with the new value when it changes. */
    onValueChange?: (value: string) => void;
    /** Accessible name when there is no visible label. */
    'aria-label'?: string;
    /** Id of the element that labels it. */
    'aria-labelledby'?: string;
    /** Content rendered inside. */
    children?: Snippet;
} & DefaultProps;

export type RadioGroupItemProps = {
    /** Value this option selects. */
    value: string;
    /** Prevents interaction and dims the control. */
    disabled?: boolean;
    /** Visible label linked to the control. */
    label?: string;
    /** Supporting text under the label, announced with the control. */
    description?: string;
    /** Id of the element. */
    id?: string;
} & DefaultProps &
    Omit<HTMLInputAttributes, 'type' | 'value' | 'name' | 'checked'>;

export type RadioGroupContext = {
    readonly name: string | undefined;
    readonly disabled: boolean;
    isSelected: (value: string) => boolean;
    setValue: (value: string) => void;
};

export { Item, Root };
~~~~

## Examples

### Descriptions

~~~~svelte
<script lang="ts">
    import * as RadioGroup from '@mielui/svelte/components/radio-group';

    let frequency = $state<string | undefined>('weekly');
    const summary = $derived(
        frequency === 'daily'
            ? 'A digest arrives each morning.'
            : frequency === 'weekly'
              ? 'A digest arrives every Monday.'
              : 'Only security notices will be sent.'
    );
</script>

<fieldset class="flex max-w-sm flex-col gap-4">
    <legend class="mb-3 text-sm font-medium">Email digest frequency</legend>
    <RadioGroup.Root bind:value={frequency} name="digest-frequency">
        <RadioGroup.Item
            value="daily"
            label="Daily"
            description="Activity from the previous day."
        />
        <RadioGroup.Item
            value="weekly"
            label="Weekly"
            description="One summary of the week's activity."
        />
        <RadioGroup.Item value="off" label="Off" description="Keep required account notices." />
    </RadioGroup.Root>
    <p role="status" class="text-sm text-foreground-muted">{summary}</p>
</fieldset>
~~~~

### Disabled

~~~~svelte
<script lang="ts">
    import * as RadioGroup from '@mielui/svelte/components/radio-group';
</script>

<RadioGroup.Root disabled value="monthly" name="billing" aria-label="Billing period">
    <RadioGroup.Item value="monthly" label="Monthly" />
    <RadioGroup.Item value="yearly" label="Yearly" />
</RadioGroup.Root>
~~~~

### Events

~~~~svelte
<script lang="ts">
    import * as RadioGroup from '@mielui/svelte/components/radio-group';

    let log = $state('No change yet');
</script>

<div class="flex max-w-sm flex-col gap-3">
    <span id="plan-label" class="text-sm font-medium">Plan</span>
    <RadioGroup.Root
        name="plan"
        aria-labelledby="plan-label"
        onValueChange={(value) => {
            log = `Changed to ${value}`;
        }}
    >
        <RadioGroup.Item value="free" label="Free" />
        <RadioGroup.Item value="team" label="Team" />
        <RadioGroup.Item value="business" label="Business" />
    </RadioGroup.Root>
    <p role="status" class="text-sm text-foreground-muted">{log}</p>
</div>
~~~~

For the rendered reference, visit [/docs/components/radio-group](/docs/components/radio-group).
