Kumo Svelte
  • Home
  • Installation
  • Colors
  • Accessibility
  • Changelog
  • Autocomplete
  • Badge
  • Banner
  • Breadcrumbs
  • Button
  • Checkbox
  • Clipboard Text
  • Cloudflare Logo
  • CodeHighlighted
  • Collapsible
  • Combobox
  • Command Palette
  • Date Picker
  • Dialog
  • Dropdown
  • Empty
  • Flow
  • Grid
  • Input
  • InputArea
  • InputGroup
  • Label
  • Layer Card
  • Link
  • Loader
  • MenuBar
  • Meter
  • Pagination
  • Popover
  • Radio
  • Select
  • Sensitive Input
  • Sidebar
  • Skeleton Line
  • Switch
  • Table
  • Table of Contents
  • Tabs
  • Text
  • Toast
  • Toolbar
  • Tooltip
  • Charts
  • Colors
  • Timeseries
  • Maps
  • Sankey
  • Custom Chart
  • Page Header
  • Resource List
  • Delete Resource
Radio
kumo-svelte

Radio

A control that allows the user to select one option from a set. Always used within a Radio.Group.

Notification preference
<script lang="ts">
  import * as Radio from "kumo-svelte/components/radio";
  let value = $state("email");
</script>

<Radio.Group legend="Notification preference" {value} onValueChange={(next) => (value = next)}>
  <Radio.Item label="Email" value="email" />
  <Radio.Item label="SMS" value="sms" />
  <Radio.Item label="Push notification" value="push" />
</Radio.Group>

Import

import * as Radio from "kumo-svelte/components/radio";

Usage

<script lang="ts">
  import * as Radio from "kumo-svelte/components/radio";
</script>

<Radio.Group legend="Choose an option" defaultValue="a">
  <Radio.Item label="Option A" value="a" />
  <Radio.Item label="Option B" value="b" />
</Radio.Group>

Examples

Default (Vertical)

Radio groups display vertically by default. Each radio has a label displayed to its right.

Account type
<script lang="ts">
  import * as Radio from "kumo-svelte/components/radio";
  let value = $state("personal");
</script>

<Radio.Group legend="Account type" {value} onValueChange={(next) => (value = next)}>
  <Radio.Item label="Personal" value="personal" />
  <Radio.Item label="Business" value="business" />
  <Radio.Item label="Enterprise" value="enterprise" />
</Radio.Group>

Horizontal

Use orientation="horizontal" for inline layouts. Items wrap when there isn’t enough space.

Size
<script lang="ts">
  import * as Radio from "kumo-svelte/components/radio";
  let value = $state("md");
</script>

<Radio.Group legend="Size" orientation="horizontal" {value} onValueChange={(next) => (value = next)}>
  <Radio.Item label="Small" value="sm" />
  <Radio.Item label="Medium" value="md" />
  <Radio.Item label="Large" value="lg" />
</Radio.Group>

With Description

Add helper text below the radio items using the description prop.

Shipping method

Choose how you'd like to receive your order

<script lang="ts">
  import * as Radio from "kumo-svelte/components/radio";
  let value = $state("standard");
</script>

<Radio.Group
  legend="Shipping method"
  description="Choose how you'd like to receive your order"
  {value}
  onValueChange={(next) => (value = next)}
>
  <Radio.Item label="Standard (5-7 days)" value="standard" />
  <Radio.Item label="Express (2-3 days)" value="express" />
  <Radio.Item label="Overnight" value="overnight" />
</Radio.Group>

Control Position

Use controlPosition="end" to place labels before radio buttons.

Preferences
<script lang="ts">
  import * as Radio from "kumo-svelte/components/radio";
</script>

<Radio.Group legend="Preferences" controlPosition="end" defaultValue="a">
  <Radio.Item label="Label before radio" value="a" />
  <Radio.Item label="Another option" value="b" />
</Radio.Group>

Radio Card

Use appearance="card" on the group to display each option as a selectable card. Combine with the description prop on each item for richer content.

Choose a plan
<script lang="ts">
  import * as Radio from "kumo-svelte/components/radio";
  let value = $state("free");
</script>

<Radio.Group legend="Choose a plan" appearance="card" {value} onValueChange={(next) => (value = next)}>
  <Radio.Item label="Free" description="For personal or hobby projects that aren't business-critical." value="free" />
  <Radio.Item label="Pro" description="For professional websites that aren't business-critical." value="pro" />
  <Radio.Item label="Business" description="For small businesses operating online." value="business" />
  <Radio.Item label="Contract" description="For mission-critical applications that are core to your business." value="contract" />
</Radio.Group>

Radio Card (Control on the Left)

Use controlPosition="start" on a card radio group to place the radio control on the left of the label and description.

Choose a plan
<script lang="ts">
  import * as Radio from "kumo-svelte/components/radio";
  let value = $state("free");
</script>

<Radio.Group
  legend="Choose a plan"
  appearance="card"
  controlPosition="start"
  {value}
  onValueChange={(next) => (value = next)}
>
  <Radio.Item label="Free" description="For personal or hobby projects that aren't business-critical." value="free" />
  <Radio.Item label="Pro" description="For professional websites that aren't business-critical." value="pro" />
</Radio.Group>

Rich Label Content

The label prop on Radio.Item accepts a string or snippet, so you can embed badges or other markup alongside the text.

Choose a plan
<script lang="ts">
  import { Badge } from "kumo-svelte/components/badge";
  import * as Radio from "kumo-svelte/components/radio";
  let value = $state("pro");
</script>

{#snippet freeLabel()}
  <span class="flex items-center gap-2">Free <Badge variant="neutral">$0</Badge></span>
{/snippet}

{#snippet proLabel()}
  <span class="flex items-center gap-2">Pro <Badge variant="primary">Popular</Badge></span>
{/snippet}

<Radio.Group legend="Choose a plan" appearance="card" {value} onValueChange={(next) => (value = next)}>
  <Radio.Item label={freeLabel} description="For personal or hobby projects." value="free" />
  <Radio.Item label={proLabel} description="For professional websites." value="pro" />
</Radio.Group>

Radio Card (Horizontal)

Combine appearance="card" with orientation="horizontal" for a side-by-side card layout.

Choose a plan
<script lang="ts">
  import * as Radio from "kumo-svelte/components/radio";
  let value = $state("free");
</script>

<Radio.Group
  legend="Choose a plan"
  appearance="card"
  orientation="horizontal"
  {value}
  onValueChange={(next) => (value = next)}
>
  <Radio.Item label="Free" description="For personal or hobby projects that aren't business-critical." value="free" />
  <Radio.Item label="Pro" description="For professional websites that aren't business-critical." value="pro" />
  <Radio.Item label="Business" description="For small businesses operating online." value="business" />
  <Radio.Item label="Contract" description="For mission-critical applications that are core to your business." value="contract" />
</Radio.Group>

With Error

Show validation errors at the group level using the error prop.

Payment method

Please select a payment method to continue

Payment method

Please select a payment method to continue

<script lang="ts">
  import * as Radio from "kumo-svelte/components/radio";
</script>

<div class="grid gap-6 md:grid-cols-2">
  <Radio.Group legend="Payment method" error="Please select a payment method to continue">
    <Radio.Item label="Credit Card" value="card" variant="error" />
    <Radio.Item label="PayPal" value="paypal" variant="error" />
  </Radio.Group>

  <Radio.Group legend="Payment method" appearance="card" error="Please select a payment method to continue">
    <Radio.Item
      label="Credit Card"
      description="Pay with Visa, Mastercard, American Express, or Elo."
      value="card"
      variant="error"
    />
    <Radio.Item label="PayPal" description="Pay with your PayPal account." value="paypal" variant="error" />
  </Radio.Group>
</div>

Disabled

Disable the entire group or individual items.

Disabled group
Individual disabled
Disabled card group
Individual disabled card
<script lang="ts">
  import * as Radio from "kumo-svelte/components/radio";
</script>

<div class="grid gap-6 md:grid-cols-2">
  <Radio.Group legend="Disabled group" disabled defaultValue="a">
    <Radio.Item label="Option A" value="a" />
    <Radio.Item label="Option B" value="b" />
  </Radio.Group>

  <Radio.Group legend="Individual disabled" defaultValue="available">
    <Radio.Item label="Available" value="available" />
    <Radio.Item label="Unavailable" value="unavailable" disabled />
  </Radio.Group>

  <Radio.Group legend="Disabled card group" appearance="card" disabled defaultValue="a">
    <Radio.Item label="Option A" description="This option is disabled." value="a" />
    <Radio.Item label="Option B" description="This option is disabled." value="b" />
  </Radio.Group>

  <Radio.Group legend="Individual disabled card" appearance="card" defaultValue="available">
    <Radio.Item label="Available" description="This option can be selected." value="available" />
    <Radio.Item label="Unavailable" description="This option is not available." value="unavailable" disabled />
  </Radio.Group>
</div>

Visually Hidden Legend

Use Radio.Legend with class="sr-only" to keep the group label accessible to screen readers while hiding it visually.

Paths
<script lang="ts">
  import * as Radio from "kumo-svelte/components/radio";
  let value = $state("all");
</script>

<Radio.Group {value} onValueChange={(next) => (value = next)}>
  <Radio.Legend class="sr-only">Paths</Radio.Legend>
  <Radio.Item label="Allow all paths" value="all" />
  <Radio.Item label="Restrict to specific paths" value="specific" />
</Radio.Group>

Custom Legend Styling

Radio.Legend accepts class for full control over label presentation. Use it instead of the legend string prop when you need custom typography, colors, or layout.

Notification preference
<script lang="ts">
  import * as Radio from "kumo-svelte/components/radio";
  let value = $state("email");
</script>

<Radio.Group {value} onValueChange={(next) => (value = next)}>
  <Radio.Legend class="text-sm font-normal text-kumo-subtle">Notification preference</Radio.Legend>
  <Radio.Item label="Email" value="email" />
  <Radio.Item label="SMS" value="sms" />
  <Radio.Item label="Push notification" value="push" />
</Radio.Group>

API Reference

Radio

PropTypeDefault
aria-labelstring—
aria-labelledbystring—
appearanceKumoRadioAppearanceKUMO_RADIO_DEFAULT_VARIANTS.appearance
children*Snippet—
classstring—
controlPositionRadioControlPosition—
defaultValuestring""
descriptionSnippet | string—
disabledbooleanfalse
errorstring—
legendstring—
namestring—
onValueChange(value: string) => void—
orientation"vertical" | "horizontal""vertical"
requiredboolean—
valuestring—

Radio.Item

PropTypeDefault
appearanceKumoRadioAppearance—
classstring—
descriptionSnippet | string—
disabledbooleanfalse
idstring—
label*Snippet | string—
value*string—
variantRadioVariantKUMO_RADIO_DEFAULT_VARIANTS.variant

Radio.Legend

PropTypeDefault
children*Snippet—
classstring—
idstring—

Usage Notes

Use value with onValueChange for controlled state. Use defaultValue for simple uncontrolled demos.

Accessibility

Semantics

Radio.Group uses Bits UI’s radio group primitive for radiogroup semantics and associates the legend prop or Radio.Legend with the group through aria-labelledby.

Keyboard Navigation

Arrow keys move between options. Space selects the focused option. Tab moves focus to and from the radio group.

Screen Readers

Each radio is announced with its label and selection state. The group label provides context for all options.

On this page

  • Import
  • Usage
  • Examples
    • Default (Vertical)
    • Horizontal
    • With Description
    • Control Position
    • Radio Card
    • Radio Card (Control on the Left)
    • Rich Label Content
    • Radio Card (Horizontal)
    • With Error
    • Disabled
    • Visually Hidden Legend
    • Custom Legend Styling
  • API Reference
    • Radio
    • Radio.Item
    • Radio.Legend
  • Usage Notes
  • Accessibility
    • Semantics
    • Keyboard Navigation
    • Screen Readers