RadioGroup

A single-select radio group as quiet rows or selectable cards, with a marker that glides. For picking one of a few.

RadioGroup playground

Select a plan
Cards carry the selection as a bordered fill that glides between them; rows glide the marker instead.

Install RadioGroup

1. New project? One command installs the package and wires everything - see Installation:

bash
pnpm dlx zyncat-ui init

2. Import the component - it loads its own stylesheet:

tsx
import { RadioGroup } from '@zyncat/ui/radio-group';

Usage

tsx
import { RadioGroup } from '@zyncat/ui/radio-group';
 
<RadioGroup name="plan" label="Select a plan" value={plan} onChange={setPlan} options={PLAN_OPTIONS} />

Compose RadioGroup in your application. No Tailwind or external styling library is required; every value resolves from Zyncat UI's token vocabulary.

RadioGroup props

RadioGroup

PropTypeDefaultDescription
...htmlAttributesOmit<FieldsetHTMLAttributes<HTMLFieldSetElement>, keyof RadioGroupOwnProps> & DataAttributes—Standard <fieldset> attributes (aria-*, data-*, ...) forwarded to the root.
name*string—Shared radio name - ties the options into one keyboard group. Required.
valuestring—The selected value (controlled).
onChange(value: string) => void—Called with the chosen option's `value`.
labelReactNode—Group label / legend (sentence case).
helperReactNode—Persistent context shown under the legend, before the options.
errorReactNode—Group-level error (e.g. required). Sets the error state + reveals the message.
variant'rows' | 'cards'—Skin: quiet rows (default) or selectable cards.
orientation'vertical' | 'horizontal'—Lay options out in a line instead of a stack.
size'sm' | 'md'—Control size: sm (dot 16) - md (default, dot 18).
disabledboolean—Disable the whole group.
options*RadioOption[]—The options to choose between.
classNamestring—Extra class(es) merged onto the root element.
styleCSSProperties—Inline styles merged onto the root element.
requiredboolean—Mark the control required - reaches the native element and shows a danger `*` after the label.
optionalboolean—Show a muted "(optional)" after the label.

RadioOption

PropTypeDefaultDescription
value*string—The stored value - what `onChange` returns and `value` matches.
label*ReactNode—Visible label (sentence case).
descriptionReactNode—Optional secondary line (muted) explaining the choice.
iconReactNode—Leading icon - your own node. CARDS only; ignored for rows.
disabledboolean—Disable just this option.

Frequently asked questions

Set variant to 'rows' (the default, a quiet stacked list) or 'cards' (bordered, selectable tiles). orientation then lays either one out 'vertical' (default) or 'horizontal', and an option's icon only renders in the cards variant.

It's one shared dot with a layout id, so picking a different option glides the marker across to it instead of it popping in and out; the 'cards' variant animates its selected-tile fill the same way.

Pass error as the message itself, not a boolean - <RadioGroup error="Pick a plan to continue." ... /> recolors the unselected dots to the danger token and reveals your message under the options through a Collapse.

Yes, natively - every option is a real <input type="radio"> sharing one name, inside a <fieldset>/<legend>, so the browser's own arrow-key roving and Tab behavior apply with no custom key handling in the component.

Set in Geist & Newsreader — animated by the house engineZyncat UI · Rev 0.11 · MIT · Built by Tabsir Ahammed · Source on GitHub