MenuChevron Down
RadioCardGroup - Docs - Artefact

RadioCardGroup

Forms
Smart auto-detect

Introduction

A radio group presented as a set of selectable cards, for exclusive choices that need more visual weight than plain radio buttons — pricing tiers, shipping speeds, and similar.

Hydration

Tier 2 — smart auto-detect. A RadioCardGroup renders as static HTML and ships no client JS unless a behavioral signal is present. Pass interactive={true} to force hydration, or interactive={false} to force a static render.

It hydrates as an island when any of the following signals is present (or interactive={true} is set):

  • value (controlled selection)
  • defaultValue (uncontrolled initial selection)
  • onValueChange
interactive propResult
omitted, no signalStatic — no client JS
omitted, a signal presentHydrates as an island
trueHydrates as an island
falseStatic — no client JS

Usage

Plan
Billing
import { RadioCardGroup } from "../components/ui";

export default function MyPage() {
  return (
    <RadioCardGroup
      label="Plan"
      defaultValue="pro"
      items={[
        { label: "Hobby", value: "hobby" },
        { label: "Pro", value: "pro" },
        { label: "Enterprise", value: "enterprise" },
      ]}
    />
  );
}

Custom Composition

Pass children for full control over each card's contents instead of the items array:

import { RadioCardGroup } from "../components/ui";

export default function MyPage() {
  return (
    <RadioCardGroup label="Plan" defaultValue="pro">
      <RadioCardGroup.Item value="hobby">
        <RadioCardGroup.ItemText>Hobby — $0/mo</RadioCardGroup.ItemText>
        <RadioCardGroup.ItemControl />
        <RadioCardGroup.ItemHiddenInput />
      </RadioCardGroup.Item>
      <RadioCardGroup.Item value="pro">
        <RadioCardGroup.ItemText>Pro — $20/mo</RadioCardGroup.ItemText>
        <RadioCardGroup.ItemControl />
        <RadioCardGroup.ItemHiddenInput />
      </RadioCardGroup.Item>
      <RadioCardGroup.Indicator />
    </RadioCardGroup>
  );
}

CMS Page Builder

This component is available as a radioCardGroup block in the Page Builder (content/pages/*.json):

{
  "type": "radioCardGroup",
  "label": "Plan",
  "defaultValue": "pro",
  "variant": "outline",
  "items": [
    { "label": "Hobby", "value": "hobby" },
    { "label": "Pro", "value": "pro" },
    { "label": "Enterprise", "value": "enterprise", "disabled": true }
  ]
}

It always renders interactive in the Page Builder.

Props

Root

PropTypeDescription
valuestringThe currently selected value (controlled).
defaultValuestringThe initially selected value (uncontrolled).
onValueChange(details: { value: string }) => voidCalled when the selection changes.
idstringThe root element's id.
namestringName of the underlying radio inputs, for native form submission.
disabledbooleanDisables every item.
readOnlybooleanPrevents selection changes while still allowing focus.
variant"subtle" | "outline" | "surface" | "solid"Visual style. Default "outline".
size"md"Visual size.
colorPalette"blue" | "green" | "red" | "purple" | "orange" | "amber" | "cyan" | "slate" | "gray"The color theme.
interactivebooleanOverrides the hydration decision (see above).
classstringCustom CSS classes for the root element.

Default composition

PropTypeDescription
items(string | RadioCardGroupItem)[]Cards to render. A plain string is shorthand for { value, label: value }.
labelstring | JSX.ElementLabel rendered above the cards.

RadioCardGroupItem

PropTypeDescription
valuestringThe item's unique value.
labelstring | JSX.ElementThe card's display content.
disabledbooleanDisables this card.
invalidbooleanMarks this card invalid.

Sub-components

PartDescription
RadioCardGroup.LabelThe group's label (<span>).
RadioCardGroup.ItemOne selectable card. role="radio", requires a value prop.
RadioCardGroup.ItemTextThe card's display text/content.
RadioCardGroup.ItemControlThe card's visual radio indicator wrapper.
RadioCardGroup.ItemHiddenInputThe visually-hidden native <input type="radio"> that holds the selection for form submission.
RadioCardGroup.IndicatorA shared sliding indicator element for the checked state.

Accessibility

  • The root has role="radiogroup"; each item has role="radio" with aria-checked reflecting selection.
  • Items use roving tabIndex — only the checked (or first enabled) item is in the tab sequence, matching native radio-group keyboard behavior.
  • data-state (checked/unchecked) and data-disabled are mirrored onto items and their text/control parts for styling.