Skip to content
buttery

v1.0.0

Source on GitHub

Version 1.0.0

RadioCardGroup

One choice among a few explained options, one of which can reveal its own field.

import { RadioCardGroup } from "@butteryui/react";

Demo

Every renewal waits for a fraud check.

Renewals after that go through without a check.

When to use it

Use it for

  • Two to five ways to set something, each needing a sentence to explain, often in a dialog
  • A choice where one option needs a detail of its own, such as how many renewals to screen
  • A dense panel or a narrow dialog, with size="sm"

Not for

  • Short options without explanations: use SegmentedControl
  • Many options: use Select
  • Several choices at once: use Checkboxes or OptionTiles

Examples

Delivery method

A wholesale order's delivery step: how a café gets its order, shipping asking for an address of its own.

Delivery

Ready from 8:00 on the roast day.

Sent the day after roasting.

Picking up

Packing

How a bag is packed, left uncontrolled: choosing the gift box opens a field for its card.

Kraft paper with a one-way valve.

Wrapped, with a handwritten note.

Pickup reminders

A small group for a narrow panel: 14px radios, 13px names, options 8 apart.

An email at 9 in the morning.

A text message.

Reminder: The day before

Renewal screening

A screening choice whose second option opens a select of its own.

Every renewal waits for a fraud check.

Renewals after that go through without a check.

Screening every renewal

Variants and states

With a detail of its own

Choose the second option to open its field.

Every renewal waits for a fraud check.

Renewals after that go through without a check.

Small

size="sm": 14px radios beside 13px names, options 8 apart, for a dense panel. Each radio keeps a 24px target.

Sent at 9 in the morning.

Sent as a text message.

Props

RadioCardGroup

PropTypeDefaultDescription
label

required

stringNames the group for screen readers, such as "Renewal screening".
options

required

readonly RadioCardOption<Value>[]The options, in order.
valueValueThe option chosen. Pair with onValueChange to control it.
defaultValueValueThe option chosen first when uncontrolled. Defaults to the first that isn't disabled.
onValueChange((value: Value) => void)Called with an option's value when it's chosen.
size"sm" | "md""md""md" (the default), 18px radios beside label-role names, options 12 apart, or "sm", 14px radios beside 13px names, options 8 apart, for a dense panel. Each radio's target stays 24px either way.

It also takes Omit<ComponentPropsWithRef<"div">, "defaultValue" | "onChange" | "dir">.

RadioCardOption

One option in a `RadioCardGroup`.

FieldTypeDefaultDescription
value

required

ValueWhat choosing it sets.
label

required

stringIts name beside the radio, in label.
descriptionReactNodeA line under it saying what it means, which describes its radio.
disabledbooleanfalseShows it but stops it being chosen. Defaults to false.
detailReactNodeA field of its own that opens under it while it's chosen, such as a Select.

Accessibility

A radio group named by label. Each option is a radio named by its label and described by its line; arrow keys move between options and choose as they go, skipping disabled ones. A chosen option's detail follows its radio in the reading order. Each radio's target is 24px.

KeysWhat they do
TabMoves to the chosen option, then into its detail if it has one, then out of the group
Arrow keysMoves to the next or previous option and chooses it, going round at the ends and skipping disabled ones
SpaceChooses the option with focus

Motion

It changes shape as one surface, on `spring.smooth`, or `spring.morph` for a big change, rather than closing and reopening.

With reduced motion: A chosen option's detail opens and closes at once, its height jumping, while its content fades in over 100ms.

Layout

It fills its container, its options stacked 12px apart. Each radio is 18px with a 24px target, its label 8px after it and wrapping, and the line and any detail under it line up with the label. At size="sm" the options are 8px apart and each radio is 14px with a 24px target, its 13px label 6px after it. A chosen option's detail opens under its line.

See it in the Halfmoon shop demo.