Notification preference
import { useState } from "react";
import { Radio } from "@cloudflare/kumo";

/** Shows a basic controlled radio group */
export function RadioBasicDemo() {
  const [value, setValue] = useState("email");
  return (
    <Radio.Group
      legend="Notification preference"
      value={value}
      onValueChange={setValue}
    >
      <Radio.Item label="Email" value="email" />
      <Radio.Item label="SMS" value="sms" />
      <Radio.Item label="Push notification" value="push" />
    </Radio.Group>
  );
}

Installation

Barrel

import { Radio } from "@cloudflare/kumo";

Granular

import { Radio } from "@cloudflare/kumo/components/radio";

Usage

import { Radio } from "@cloudflare/kumo";

export default function Example() {
  return (
    <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
import { useState } from "react";
import { Radio } from "@cloudflare/kumo";

/** Shows the default vertical radio group layout */
export function RadioDefaultDemo() {
  const [value, setValue] = useState("personal");
  return (
    <Radio.Group legend="Account type" value={value} onValueChange={setValue}>
      <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
import { useState } from "react";
import { Radio } from "@cloudflare/kumo";

/** Shows a horizontal radio group layout */
export function RadioHorizontalDemo() {
  const [value, setValue] = useState("md");
  return (
    <Radio.Group
      legend="Size"
      orientation="horizontal"
      value={value}
      onValueChange={setValue}
    >
      <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

import { useState } from "react";
import { Radio } from "@cloudflare/kumo";

/** Shows a radio group with helper description text */
export function RadioDescriptionDemo() {
  const [value, setValue] = useState("standard");
  return (
    <Radio.Group
      legend="Shipping method"
      description="Choose how you'd like to receive your order"
      value={value}
      onValueChange={setValue}
    >
      <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
import { Radio } from "@cloudflare/kumo";

/** Shows radio group with labels positioned before the radio control */
export function RadioControlPositionDemo() {
  return (
    <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
import { useState } from "react";
import { Radio } from "@cloudflare/kumo";

/** Shows radio card appearance with Cloudflare plan options */
export function RadioCardDemo() {
  const [value, setValue] = useState("free");
  return (
    <Radio.Group
      legend="Choose a plan"
      appearance="card"
      value={value}
      onValueChange={setValue}
    >
      <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 (Horizontal)

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

Choose a plan
import { useState } from "react";
import { Radio } from "@cloudflare/kumo";

/** Shows radio card appearance in horizontal layout */
export function RadioCardHorizontalDemo() {
  const [value, setValue] = useState("free");
  return (
    <Radio.Group
      legend="Choose a plan"
      appearance="card"
      orientation="horizontal"
      value={value}
      onValueChange={setValue}
    >
      <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

import { Radio } from "@cloudflare/kumo";

/** Shows error state for both default and card radio groups */
export function RadioErrorDemo() {
  return (
    <div className="grid grid-cols-2 gap-6">
      <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
import { Radio } from "@cloudflare/kumo";

/** Shows disabled state for both default and card radio groups */
export function RadioDisabledDemo() {
  return (
    <div className="grid grid-cols-2 gap-6">
      <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>
  );
}

API Reference

Radio.Group

Container for radio buttons with legend, description, and error support.

PropTypeDefault
legend*string-
children*ReactNode-
orientation"vertical" | "horizontal"-
appearanceKumoRadioAppearance-
errorstring-
descriptionReactNode-
valuestring-
disabledboolean-
label*"start" (default) puts radio before label-
Note*In card appearance-
controlPositionRadioControlPosition-
namestring-
classNamestring-

Radio.Item

Individual radio button within Radio.Group.

PropTypeDefault

No component-specific props. Accepts standard HTML attributes.

Accessibility

Semantic HTML

Radio.Group uses semantic <fieldset> and <legend> elements for proper grouping and screen reader announcement.

Keyboard Navigation

Arrow Up/Down or Arrow Left/Right moves 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 legend provides context for all options.