Kanzo UI
Forms

Radio Group

A set of options where exactly one can be chosen.

Ark UI

Usage

import { RadioGroup, RadioGroupItem, RadioGroupLabel } from "@kanzo-tech/ui";
<RadioGroup defaultValue="warden">
  <RadioGroupItem value="warden">Warden</RadioGroupItem>
</RadioGroup>

Anatomy

RadioGroup
├── RadioGroupLabel
├── RadioGroupItem
│   └── RadioGroupText
└── RadioGroupCard          — the same item, styled as a card
    ├── RadioGroupText
    └── RadioGroupIndicator — optional, place it yourself

With label

Minimum rank

Horizontal

orientation tells the machine which arrow keys move the selection; the row layout itself is a class, because the group is vertical by default.

Invalid

Disabled

Cards

A "card radio" is not another component: it is RadioGroupCard — this same machine, this same item, with the selected look driven by data-[state=checked] instead of a dot. Full radio semantics still come from Ark — roving focus, arrow-key selection, hidden inputs — so the card is purely how the option looks, never how it behaves.

The contents are children, not an options array. A record of label / description / icon / badge / preview nodes is a layout tree written as an attribute: you cannot reorder it, wrap a region, spread props onto one, or use asChild. Children give all of that back, and a badge, an icon or a type specimen is then whatever you render.

columns is the one thing the card layout needs that classes do not already give you: "auto" fits as many card-width tracks as the container allows, and a number pins the count. Without it the group stays the default column. Note that this is layout, and distinct from Ark's orientation, which is arrow-key direction.

<RadioGroup columns="auto">…</RadioGroup>   {/* as many as fit */}
<RadioGroup columns={3}>…</RadioGroup>      {/* exactly three */}

The count is written to a --columns custom property rather than a class, so a responsive count needs no second prop:

<RadioGroup columns={1} className="sm:[--columns:2] lg:[--columns:4]">

The layout inside a card is ordinary flex. RadioGroupCard is already a flex row, so a horizontal card is items-start and a vertical one is flex-col items-center text-center — and since the cards are the group's direct children, one *: class list on the group beats repeating it per card:

<RadioGroup className="text-center *:flex-col *:items-center" columns="auto">

Rows, and the indicator

RadioGroupIndicator is the radio dot with no semantics of its own. Place it inside a card when the selected border and fill do not say enough on their own — and place it where you want it, which is why it is not a prop.

Previews

Anything can go in a card: a type specimen, a swatch, a mini chart.

Controlled

Thornmarch

Disabled and invalid

disabled sits on the individual RadioGroupCard, invalid on the group. A badge is free of any coupling to either — it marks a recommended option just as easily as an unavailable one.

API Reference

RadioGroup extends RadioGroup.Root (value, defaultValue, onValueChange, orientation, disabled, invalid, readOnly, required, name, form) and adds one prop:

PropTypeDefault
columnsnumber | "auto"— (a column)

RadioGroupItem extends RadioGroup.Item (value, disabled, invalid) — the control, the item text and the hidden input are rendered for you. RadioGroupCard extends the same RadioGroup.Item and renders only the hidden input, so the card's contents are yours; RadioGroupText and RadioGroupIndicator take no props beyond Ark's.

On this page