Radio Card

Radio cards combine a radio button with a card layout, allowing users to select exactly one option from a set with rich contextual information. Ideal for plan selection, payment methods, or any single-select scenario where visual hierarchy matters.

Basic Usage

Radio Card offers two APIs: a simple pre-composed component for common use cases, and an advanced compound component API for full control.

import { SimpleRadioCard, SimpleRadioCardGroup } from '@/components'

<SimpleRadioCardGroup value={value} onValueChange={setValue}>
  <SimpleRadioCard
    value="option1"
    label="Enable notifications"
    subtext="Receive updates about your account activity"
  />
  <SimpleRadioCard
    value="option2"
    label="Disable notifications"
    subtext="You won't receive any notifications"
  />
</SimpleRadioCardGroup>

Variants

Radio cards support four visual variants to accommodate different content types.

Text variant (default)

Icon variant

Avatar variant

Card Provider variant

Text (Default)

Simple text-only card with label, subtext, and optional badge.

<RadioCardGroup>
  <RadioCard
    value="option"
    label="Text option"
    subtext="Simple text-only card"
    badge="Default"
  />
</RadioCardGroup>

Icon

Card with a circular icon container, great for integrations or feature toggles.

<RadioCardGroup>
  <RadioCard
    value="gitlab"
    variant="icon"
    label="GitLab Integration"
    subtext="Connect your GitLab account"
    icon={<GitLabIcon />}
  />
</RadioCardGroup>

Avatar

Card with an avatar image, perfect for user selection or team members.

<RadioCardGroup>
  <RadioCard
    value="sofia"
    variant="avatar"
    label="Sofia Martinez"
    subtext="Product Designer"
    avatar={<img src="..." alt="Sofia" />}
  />
</RadioCardGroup>

Card Provider

Card with a payment provider or brand icon.

<RadioCardGroup>
  <RadioCard
    value="applepay"
    variant="cardProvider"
    label="Apple Pay"
    subtext="Pay with Apple Pay"
    cardProvider={<ApplePayIcon />}
  />
</RadioCardGroup>

States

Radio cards support multiple visual states to indicate selection, errors, and disabled states.

Default - Unselected

Default - Selected

Error

Disabled - Unselected

Disabled - Selected

Selected

When selected, the card displays a blue border to indicate selection.

<RadioCardGroup value="option">
  <RadioCard value="option" label="Selected option" />
</RadioCardGroup>

Error

Use the error state for validation errors or required fields.

<RadioCardGroup>
  <RadioCard value="option" label="Required field" error />
</RadioCardGroup>

Disabled

Disabled cards cannot be interacted with and display muted styling.

<RadioCardGroup>
  <RadioCard value="option" label="Disabled option" disabled />
</RadioCardGroup>

<RadioCardGroup value="option">
  <RadioCard value="option" label="Disabled selected" disabled />
</RadioCardGroup>

Clickable Behavior

Control whether the entire card or just the radio button is interactive.

clickableCard=true (default)

clickableCard=false

Entire Card (Default)

By default, clicking anywhere on the card selects the radio.

<RadioCard
  value="option"
  label="Click anywhere"
  clickableCard={true}  // default
/>

Radio Only

Set clickableCard={false} to make only the radio button interactive.

<RadioCard
  value="option"
  label="Click radio only"
  clickableCard={false}
/>

With Badge

Badges can highlight important information like recommendations or pricing.

<RadioCardGroup>
  <RadioCard
    value="premium"
    label="Premium Plan"
    subtext="Access all features"
    badge="Recommended"
  />
  <RadioCard
    value="basic"
    label="Basic Plan"
    subtext="Essential features"
    badge="Free"
  />
</RadioCardGroup>

Controlled State

Manage selection with controlled state.

Selected: option1

const [selected, setSelected] = useState('option1')

<RadioCardGroup value={selected} onValueChange={setSelected}>
  <RadioCard value="option1" label="Option 1" />
  <RadioCard value="option2" label="Option 2" />
  <RadioCard value="option3" label="Option 3" />
</RadioCardGroup>

All States Overview

Text
Icon
Avatar
Card Provider
Default
Selected
Error
Disabled

Advanced Compound Component API

For complex layouts or when you need full control over the card structure, use the compound component API.

Basic Compound Usage

import { RadioCard } from '@/components'

<RadioCard.Group value={value} onValueChange={setValue}>
  <RadioCard.Item value="notifications">
    <RadioCard.Leading>
      <RadioCard.Content>
        <RadioCard.TitleRow>
          <RadioCard.Label>Enable notifications</RadioCard.Label>
        </RadioCard.TitleRow>
        <RadioCard.Description>
          Receive updates about your account activity
        </RadioCard.Description>
      </RadioCard.Content>
    </RadioCard.Leading>
    <RadioCard.Indicator />
  </RadioCard.Item>
</RadioCard.Group>

With Icons and Badges

The compound API makes it easy to combine icons, badges, and custom content.

<RadioCard.Group value={value} onValueChange={setValue}>
  <RadioCard.Item value="settings">
    <RadioCard.Leading variant="icon">
      <RadioCard.Icon>
        <SettingsIcon />
      </RadioCard.Icon>
      <RadioCard.Content>
        <RadioCard.TitleRow>
          <RadioCard.Label>General Settings</RadioCard.Label>
          <RadioCard.Badge>Default</RadioCard.Badge>
        </RadioCard.TitleRow>
        <RadioCard.Description>
          Configure your general preferences
        </RadioCard.Description>
      </RadioCard.Content>
    </RadioCard.Leading>
    <RadioCard.Indicator />
  </RadioCard.Item>
</RadioCard.Group>

Custom Layout with Right Slot

Use RadioCard.RightSlot for custom content like pricing or actions.

<RadioCard.Group value={value} onValueChange={setValue}>
  <RadioCard.Item value="pro">
    <RadioCard.Leading>
      <RadioCard.Content>
        <RadioCard.TitleRow>
          <RadioCard.Label>Pro Plan</RadioCard.Label>
          <RadioCard.Badge>Popular</RadioCard.Badge>
        </RadioCard.TitleRow>
        <RadioCard.Description>
          Advanced features for professionals
        </RadioCard.Description>
      </RadioCard.Content>
    </RadioCard.Leading>
    <RadioCard.RightSlot>
      <span className="font-semibold">$19/mo</span>
    </RadioCard.RightSlot>
    <RadioCard.Indicator />
  </RadioCard.Item>
</RadioCard.Group>

Available Compound Components

ComponentDescription
RadioCard.GroupRoot container wrapping all items
RadioCard.ItemIndividual card wrapper
RadioCard.IndicatorThe radio button indicator
RadioCard.LabelLabel text
RadioCard.DescriptionSecondary description text
RadioCard.BadgeBadge component with state-aware styling
RadioCard.ContentContainer for label, description, and badge
RadioCard.TitleRowHorizontal row for label and badge
RadioCard.LeadingContainer for leading content (icon/avatar + text)
RadioCard.IconCircular icon container
RadioCard.AvatarCircular avatar container
RadioCard.ProviderPayment provider icon container
RadioCard.RightSlotCustom content on the right side

Accessibility

  • Built on Radix UI Radio Group primitive for robust accessibility
  • Full keyboard support (Arrow keys to navigate, Space to select)
  • When clickableCard={true}, the entire card is interactive via a label element
  • Proper ARIA attributes for screen readers
  • Focus states are clearly visible
  • Only one option can be selected at a time within a group

API Reference

SimpleRadioCardGroup Props

PropTypeDefaultDescription
valuestring-The controlled selected value
defaultValuestring-The default selected value (uncontrolled)
onValueChange(value: string) => void-Callback when selection changes
disabledbooleanfalseDisable all cards in the group
orientation"horizontal" | "vertical""vertical"Layout orientation
namestring-Name for form submission
classNamestring-Additional CSS classes

SimpleRadioCard Props

PropTypeDefaultDescription
valuestringRequiredThe value of this option
labelstringRequiredThe main label text
subtextstring-Secondary descriptive text
badgestring-Badge text displayed next to the label
variant"text" | "icon" | "avatar" | "cardProvider""text"Visual variant
disabledbooleanfalseWhether the card is disabled
errorbooleanfalseWhether to show error styling
clickableCardbooleantrueWhether clicking the card selects the radio
iconReactNode-Icon element for the icon variant
avatarReactNode-Avatar element for the avatar variant
cardProviderReactNode-Provider icon for the cardProvider variant
rightSlotReactNode-Custom content in the right slot
classNamestring-Additional CSS classes

RadioCard.Group Props

Same as SimpleRadioCardGroup - wraps Radix UI RadioGroup.Root.

RadioCard.Item Props

PropTypeDefaultDescription
valuestringRequiredThe value of this option
disabledbooleanfalseWhether the card is disabled
errorbooleanfalseWhether to show error styling
clickableCardbooleantrueWhether clicking the card selects the radio
classNamestring-Additional CSS classes

Context Hooks

HookDescription
useRadioCardGroupContext()Access group-level state (value, disabled, name)
useRadioCardItemContext()Access item-level state (value, disabled, error, isSelected, state)