Radio Group

Allows users to select a single option from a list of mutually exclusive choices.

	<script lang="ts">
  import { Label, RadioGroup } from "bits-ui";
</script>
 
<RadioGroup.Root class="flex flex-col gap-4 text-sm font-medium">
  <div
    class="group flex select-none items-center text-foreground transition-all"
  >
    <RadioGroup.Item
      id="amazing"
      value="amazing"
      class="size-5 shrink-0 cursor-default rounded-full border border-border-input bg-background transition-all duration-100 ease-in-out hover:border-dark-40 data-[state=checked]:border-6 data-[state=checked]:border-foreground"
    />
    <Label.Root for="amazing" class="pl-3">Amazing</Label.Root>
  </div>
  <div
    class="group flex select-none items-center text-foreground transition-all"
  >
    <RadioGroup.Item
      id="average"
      value="average"
      class="size-5 shrink-0 cursor-default rounded-full border border-border-input bg-background transition-all duration-100 ease-in-out hover:border-dark-40 data-[state=checked]:border-6 data-[state=checked]:border-foreground"
    />
    <Label.Root for="average" class="pl-3">Average</Label.Root>
  </div>
  <div
    class="group flex select-none items-center text-foreground transition-all"
  >
    <RadioGroup.Item
      id="terrible"
      value="terrible"
      class="size-5 shrink-0 cursor-default rounded-full border border-border-input bg-background transition-all duration-100 ease-in-out hover:border-dark-40 data-[state=checked]:border-6 data-[state=checked]:border-foreground"
    />
    <Label.Root for="terrible" class="pl-3">Terrible</Label.Root>
  </div>
</RadioGroup.Root>

Structure

	<script lang="ts">
	import { RadioGroup } from "bits-ui";
</script>
 
<RadioGroup.Root>
	<RadioGroup.Item>
		{#snippet children({ checked })}
			{#if checked}

			{/if}
		{/snippet}
	</RadioGroup.Item>
</RadioGroup.Root>

Reusable Components

It's recommended to use the RadioGroup primitives to create your own custom components that can be used throughout your application.

In the example below, we're creating a custom MyRadioGroup component that takes in an array of items and renders a radio group with those items along with a Label component for each item.

MyRadioGroup.svelte
	<script lang="ts">
	import { RadioGroup, Label, type WithoutChildrenOrChild, useId } from "bits-ui";
 
	type Item = {
		value: string;
		label: string;
		disabled?: boolean;
	};
 
	type Props = WithoutChildrenOrChild<RadioGroup.RootProps> & {
		items: Item[];
	};
 
	let { value = $bindable(""), ref = $bindable(null), items, ...restProps }: Props = $props();
</script>
 
<RadioGroup.Root bind:value bind:ref {...restProps}>
	{#each items as item}
		{@const id = useId()}
		<div>
			<RadioGroup.Item {id} value={item.value} disabled={item.disabled}>
				{#snippet children({ checked })}
					{#if checked}

					{/if}
				{/snippet}
			</RadioGroup.Item>
			<Label.Root for={id}>{item.label}</Label.Root>
		</div>
	{/each}
</RadioGroup.Root>

You can then use the MyRadioGroup component in your application like so:

+page.svelte
	<script lang="ts">
	import MyRadioGroup from "$lib/components/MyRadioGroup.svelte";
 
	const myItems = [
		{ value: "apple", label: "Apple" },
		{ value: "banana", label: "Banana" },
		{ value: "coconut", label: "Coconut", disabled: true },
	];
</script>
 
<MyRadioGroup items={myItems} name="favoriteFruit" />

Value State

The value prop is used to determine which radio group item(s) are currently checked. Bits UI provides flexible options for controlling and synchronizing the Radio Group's value.

Two-Way Binding

Use the bind:value directive for effortless two-way synchronization between your local state and the Radio Group's internal state.

	<script lang="ts">
	import { RadioGroup } from "bits-ui";
	let myValue = $state<string>("");
</script>
 
<button onclick={() => (myValue = "apple")}> Apple </button>
 
<RadioGroup.Root bind:value={myValue}>
	<!-- ... -->
</RadioGroup.Root>

This setup enables toggling the Radio Group's value to "apple" via the custom button and ensures the local myValue state updates when the Radio Group changes through any internal means (e.g., clicking on an item's button).

Change Handler

You can also use the onValueChange prop to update local state when the Radio Group's value state changes. This is useful when you don't want two-way binding for one reason or another, or you want to perform additional logic when the Radio Group changes.

	<script lang="ts">
	import { RadioGroup } from "bits-ui";
	let myValue = $state<string>("");
</script>
 
<RadioGroup.Root
	value={myValue}
	onValueChange={(value) => {
		myValue = value;
		// additional logic here.
	}}
>
	<!-- ... -->
</RadioGroup.Root>

Controlled

Sometimes, you may want complete control over the component's value state, meaning you will be "kept in the loop" and be required to apply the state change yourself. While you will rarely need this, it's possible to do so by setting the controlledValue prop to true.

You will then be responsible for updating a local value state variable that is passed as the value prop to the RadioGroup.Root component.

	<script lang="ts">
	import { RadioGroup } from "bits-ui";
 
	let myValue = $state("");
</script>
 
<RadioGroup.Root controlledValue value={myValue} onValueChange={(v) => (myValue = v)}>
	<!-- ... -->
</RadioGroup.Root>

See the Controlled State documentation for more information about controlled states.

HTML Forms

If you set the name prop on the RadioGroup.Root component, a hidden input element will be rendered to submit the value of the radio group to a form.

	<RadioGroup.Root name="favoriteFruit">
	<!-- ... -->
</RadioGroup.Root>

Required

To make the hidden input element required you can set the required prop on the RadioGroup.Root component.

	<RadioGroup.Root required>
	<!-- ... -->
</RadioGroup.Root>

Disabling Items

You can disable a radio group item by setting the disabled prop to true.

	<RadioGroup.Item value="apple" disabled>Apple</RadioGroup.Item>

Orientation

The orientation prop is used to determine the orientation of the radio group, which influences how keyboard navigation will work.

When the orientation is set to 'vertical', the radio group will navigate through the items using the ArrowUp and ArrowDown keys. When the orientation is set to 'horizontal', the radio group will navigate through the items using the ArrowLeft and ArrowRight keys.

	<RadioGroup.Root orientation="vertical">
	<!-- ... -->
</RadioGroup.Root>
 
<RadioGroup.Root orientation="horizontal">
	<!-- ... -->
</RadioGroup.Root>

API Reference

RadioGroup.Root

The radio group component used to group radio items under a common name for form submission.

Property Type Description
value $bindable
string

The value of the currently selected radio item. You can bind to this value to control the radio group's value from outside the component.

Default: undefined
onValueChange
function

A callback that is fired when the radio group's value changes.

Default: undefined
controlledValue
boolean

Whether or not the value is controlled or not. If true, the component will not update the value state internally, instead it will call onValueChange when it would have otherwise, and it is up to you to update the value prop that is passed to the component.

Default: false
disabled
boolean

Whether or not the radio group is disabled. This prevents the user from interacting with it.

Default: false
required
boolean

Whether or not the radio group is required.

Default: false
name
string

The name of the radio group used in form submission. If provided, a hidden input element will be rendered to submit the value of the radio group.

Default: undefined
loop
boolean

Whether or not the radio group should loop through the items when navigating with the arrow keys.

Default: false
orientation
enum

The orientation of the radio group. This will determine how keyboard navigation will work within the component.

Default: 'vertical'
ref $bindable
HTMLDivElement

The underlying DOM element being rendered. You can bind to this to get a reference to the element.

Default: undefined
children
Snippet

The children content to render.

Default: undefined
child
Snippet

Use render delegation to render your own element. See delegation docs for more information.

Default: undefined
Data Attribute Value Description
data-orientation
enum

The orientation of the radio group.

data-radio-group-root
''

Present on the root element.

RadioGroup.Item

An radio item, which must be a child of the RadioGroup.Root component.

Property Type Description
value required
string

The value of the radio item. This should be unique for each radio item in the group.

Default: undefined
disabled
boolean

Whether the radio item is disabled.

Default: false
ref $bindable
HTMLButtonElement

The underlying DOM element being rendered. You can bind to this to get a reference to the element.

Default: undefined
children
Snippet

The children content to render.

Default: undefined
child
Snippet

Use render delegation to render your own element. See delegation docs for more information.

Default: undefined
Data Attribute Value Description
data-disabled
''

Present when the radio item is disabled.

data-value
''

The value of the radio item.

data-state
enum

The radio item's checked state.

data-orientation
enum

The orientation of the parent radio group.

data-radio-group-item
''

Present on the radio item element.