Skip to content

shadcn.io is an independent project built on shadcn/ui

Free

Radio Group with Custom Content for React

Free, Pro and Enterprise as selectable rows. Pro starts selected at $12/mo, with a price badge, a description and a feature list on each.

Three rows, each with a radio, a title, a price badge, a description and a feature list. Pro starts selected at $12/mo. Free is $0/mo and Enterprise is Custom.

Use a rich row when people compare plans, not single words. A Card grid fits if the plans should sit side by side. On React, Base UI does not price the plans.

Preview

Preview width

Installation

Sign in to get your install command
Free with an account. It carries your token, so the CLI installs everything in one go.
Use email insteadNo credit card

Anatomy

Radio Group anatomy: root, label, item control, indicator, item, item text

Usage

<RadioGroup className="max-w-sm" defaultValue="pro">
  {plans.map((plan) => (
    <FieldLabel htmlFor={`custom-plan-${plan.value}`} key={plan.value}>
      <Field orientation="horizontal">
        <RadioGroupItem id={`custom-plan-${plan.value}`} value={plan.value} />
        <FieldContent className="gap-2">
          <div className="flex items-center justify-between gap-2">
            <FieldTitle>{plan.title}</FieldTitle>
            <Badge variant={plan.badge}>{plan.price}</Badge>
          </div>
          <FieldDescription>{plan.description}</FieldDescription>
          <ul className="flex list-disc flex-col gap-1 ps-4 text-muted-foreground text-xs">
            {plan.features.map((feature) => (
              <li key={feature}>{feature}</li>
            ))}
          </ul>
        </FieldContent>
      </Field>
    </FieldLabel>
  ))}
</RadioGroup>

FAQ

Which plan starts selected?

defaultValue is pro. The values are free, pro, and enterprise, and every card is built from a list of plans at the top of the file.

How is the price placed?

The FieldTitle and the Badge share a row with justify-between. Free shows $0/mo and Enterprise shows Custom with variant secondary. Pro shows $12/mo with the default variant, so the recommended plan stands out.

Where does the feature list come from?

Each plan has a features array, rendered as a ul with list-disc, text-xs and text-muted-foreground. Pro and Enterprise list four features, Free lists three. Nothing hides a line based on the selection.

Why does the radio sit at the top of the card?

Field is horizontal, and when it holds a FieldContent it aligns its items to the start, so the radio lines up with the plan name, not the middle of the list.

What selects the plan?

The whole card. FieldLabel wraps the Field, so the name, badge, sentence and feature list all check the radio. The FieldLabel points at the item with htmlFor, and the item has the matching id.

How do I change the space between plans?

RadioGroup uses its default gap and max-w-sm. Add a gap-* class on it. The border, padding and hover of each card come from FieldLabel.

API Reference

Radio Group

Sets defaultValue="pro", id, custom-plan-, plan, value and value={plan.value}. The rest is on the Radio Group page.

Field

Sets htmlFor, custom-plan-, plan, value and orientation="horizontal". The rest is on the Field page.

Badge

Sets variant={plan.badge}. The rest is on the Badge page.