Radio cards
A choice between a few options, each drawn as a card with a mark, a name and a line about it, with exactly one chosen.
On this page
Code
import { RadioCards, type RadioCardOption } from "@bosunkit/components/radio-cards";
import { FilePlus, LayoutTemplate, Sparkles } from "lucide-react";
import { useState, type Dispatch, type ReactElement, type SetStateAction } from "react";
export const description: string =
"How to start a maintenance record: three cards, each with a mark, a name and a line, and exactly one chosen.";
const OPTIONS: readonly RadioCardOption[] = [
{
value: "describe",
label: "Describe it",
description: "Bosun drafts the record from plain words.",
icon: <Sparkles size="1.25em" />,
},
{
value: "template",
label: "From a template",
description: "Start from a tested schedule for your engine.",
icon: <LayoutTemplate size="1.25em" />,
},
{
value: "blank",
label: "Blank record",
description: "Fill in every field yourself.",
icon: <FilePlus size="1.25em" />,
},
];
export default function Showcase(): ReactElement {
const [value, setValue]: [string, Dispatch<SetStateAction<string>>] = useState<string>("describe");
return <RadioCards label="How do you want to start?" options={OPTIONS} value={value} onValueChange={setValue} />;
}
Radio cards are a radio group drawn as cards, for a choice where each option needs a sentence: how to start a record,
which kind to create, where it goes. The chosen card has the accent on its border, a tint and an accent mark, and a
screen reader hears it as checked, so the choice never rests on the color. The arrow keys move the choice, and the group
is named by label while each card is named by its own name and line. It is built on Base UI's radio group.
The caller translates every word. A card the crew cannot choose now stays in the group, dimmed and announced as disabled, so they can see it exists. For two to five short options in one row, use the segmented control, which is smaller.
Examples
Two columns
Code
import { RadioCards } from "@bosunkit/components/radio-cards";
import type { ReactElement } from "react";
export const description: string =
"`columns` of 2 for options with longer lines, with one card unavailable: it stays in the group, dimmed, and cannot be chosen.";
export default function TwoColumns(): ReactElement {
return (
<RadioCards
label="Where does the record go?"
columns={2}
defaultValue="engine"
options={[
{ value: "engine", label: "Engine", description: "Service intervals, filters, belts and the cooling circuit." },
{ value: "rigging", label: "Rigging", description: "Standing and running rigging, sails and furling gear." },
{
value: "safety",
label: "Safety equipment",
description: "Needs a safety officer to sign it off.",
disabled: true,
},
]}
/>
);
}
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| labelrequired | string | – | The group's name for a screen reader ("How do you want to start?"), translated by the caller. |
| optionsrequired | readonly RadioCardOption[] | – | The cards, in reading order. |
| value | string | undefined | – | The chosen value, for a caller that holds it; pair it with onValueChange. |
| defaultValue | string | undefined | – | The value chosen at first, when the caller does not hold it. |
| onValueChange | RadioGroupProps["onValueChange"] | – | Called with the value the crew choose. |
| columns | 1 | 2 | 3 | 4 | undefined | 3 | How many cards sit side by side where there is room; 3 by default. Fewer sit side by side in a narrow box. |
| disabled | boolean | undefined | false | Whether every card is unavailable, such as while a choice is being saved. |
| className | string | undefined | – | Added to the group's classes. |
| testId | string | undefined | – | Becomes data-testid on the group. |
| ref | Ref<HTMLDivElement> | undefined | – | The group element. |
| hint | string | undefined | – | Supporting instructions announced with the group. |
| error | string | undefined | – | Validation message; marks the group invalid. |
| name | string | undefined | – | Submitted field name. |
| form | string | undefined | – | ID of an owning form outside the component's ancestors. |
| required | boolean | undefined | – | Requires a choice before native form submission. |
| readOnly | boolean | undefined | – | Keeps the value focusable and submitted, but prevents changes. |
Related
-
Radio group: a compact visible list for one choice.
-
Segmented radio group: two to five short options in one row.
-
Wizard step: the step panel choice cards usually sit in.
-
Select: a longer list of choices that opens from a button.