icon

Morainev0.5.0

RadioGroup
formsradio-group

RadioGroup

Single-select radio group with card, list, and table layout variants.

Import#

import { RadioGroup } from 'moraine'

Slot Structure#

Radiogroup root with mutually exclusive radio items. Use FormField for the group label, description, help text, and validation message.

root
└── item (×n)
├── input
├── control
│ └── indicator
└── wrapper (optional)
├── label (optional)
└── description (optional)

Examples#

Variants#

List, card, and table variants for single selection.

function Variants() {
const ITEMS = [
{ value: 'starter', label: 'Starter', description: 'For personal projects' },
{ value: 'pro', label: 'Pro', description: 'For teams and scaling' },
{ value: 'enterprise', label: 'Enterprise', description: 'For regulated workloads' },
]
return (
<div class="gap-4 grid lg:grid-cols-3 sm:grid-cols-2">
<div class="p-4 b-(1 border) rounded-lg">
<FormField label="List">
<RadioGroup items={ITEMS} defaultValue="starter" />
</FormField>
</div>
<div class="p-4 b-(1 border) rounded-lg">
<FormField label="Card">
<RadioGroup items={ITEMS} variant="card" defaultValue="pro" />
</FormField>
</div>
<div class="p-4 b-(1 border) rounded-lg">
<FormField label="Table">
<RadioGroup
items={ITEMS}
variant="table"
orientation="vertical"
defaultValue="enterprise"
/>
</FormField>
</div>
</div>
)
}

Sizes + Orientation#

Size scale and vertical/horizontal modes.

function SizesOrientation() {
const ITEMS = [
{ value: 'starter', label: 'Starter', description: 'For personal projects' },
{ value: 'pro', label: 'Pro', description: 'For teams and scaling' },
{ value: 'enterprise', label: 'Enterprise', description: 'For regulated workloads' },
]
const SIZES: RadioGroupSizeName[] = ['xs', 'sm', 'md', 'lg', 'xl']
type RadioGroupSizeName = Exclude<RadioGroupT.Variant['size'], undefined>
return (
<div class="gap-4 grid lg:grid-cols-2">
<div class="space-y-3">
<For each={SIZES}>
{(size) => (
<div class="p-4 b-(1 border) rounded-lg">
<FormField label={`Size ${size}`}>
<RadioGroup items={ITEMS} size={size} defaultValue="starter" />
</FormField>
</div>
)}
</For>
</div>
<div class="space-y-3">
<div class="p-4 b-(1 border) rounded-lg">
<FormField label="Horizontal card">
<RadioGroup items={ITEMS} variant="card" orientation="horizontal" defaultValue="pro" />
</FormField>
</div>
<div class="p-4 b-(1 border) rounded-lg">
<FormField label="Horizontal table">
<RadioGroup
items={ITEMS}
variant="table"
orientation="horizontal"
defaultValue="enterprise"
/>
</FormField>
</div>
</div>
</div>
)
}

Controlled + Disabled#

Controlled value with disabled option in data set.

function ControlledDisabled() {
const ITEMS = [
{ value: 'starter', label: 'Starter', description: 'For personal projects' },
{ value: 'pro', label: 'Pro', description: 'For teams and scaling' },
{ value: 'enterprise', label: 'Enterprise', description: 'For regulated workloads' },
]
const [value, setValue] = createSignal('pro')
return (
<div class="max-w-xl space-y-3">
<FormField label="Plan selector">
<RadioGroup
items={[
...ITEMS,
{
value: 'legacy',
label: 'Legacy',
description: 'No longer available',
disabled: true,
},
]}
value={value()}
onChange={setValue}
variant="table"
orientation="horizontal"
/>
</FormField>
<p class="text-xs text-muted-foreground">Current plan: {value()}</p>
</div>
)
}

Indicator Positions#

Start/end/hidden indicator styles with card variant.

function IndicatorPositions() {
const ITEMS = [
{ value: 'starter', label: 'Starter', description: 'For personal projects' },
{ value: 'pro', label: 'Pro', description: 'For teams and scaling' },
{ value: 'enterprise', label: 'Enterprise', description: 'For regulated workloads' },
]
const INDICATORS: RadioGroupIndicatorName[] = ['start', 'end', 'hidden']
type RadioGroupIndicatorName = Exclude<RadioGroupT.Variant['indicator'], undefined>
return (
<div class="gap-4 grid lg:grid-cols-3 sm:grid-cols-2">
<For each={INDICATORS}>
{(indicator) => (
<div class="p-4 b-(1 border) rounded-lg">
<FormField label={`Indicator ${indicator}`}>
<RadioGroup items={ITEMS} variant="card" indicator={indicator} defaultValue="pro" />
</FormField>
</div>
)}
</For>
</div>
)
}

API Reference#

Attributes#

Slotroot5 attributes
Radio group container that owns selection state and layout.

ARIA Attributes

5
ARIA AttributeDescription
aria-disabled
Indicates that the control is disabled.
aria-orientation
Communicates horizontal or vertical orientation.
aria-readonly
Indicates that the control value cannot be changed by the user.
aria-required
Indicates that user input is required.
role
Defines the semantic role exposed to assistive technology.

Props#

PropTypeDefaultDescription
classClassValue
Class applied to the component root or trigger element.
classesRadioGroupT.Classes | undefined
defaultValuestring | undefined
The default value of the input (uncontrolled).
disabledboolean | undefinedfalse
Whether the input is disabled.
idstring | undefined
The ID of the input element.
indicatorRadioGroupItemIndicator | undefined
items(string | RadioGroupT.Item)[] | undefined
Array of items to render in the group.
namestring | undefined
The name of the input element, used for form submission.
onChange((value: string) => void) | undefined
Callback when the selected value changes.
orientation"horizontal" | "vertical" | undefinedvertical
The orientation of the radio group.
readOnlyboolean | undefinedfalse
Whether the input is read-only.
refJSX.HTMLElementTags["div"] extends { ref?: infer Ref; } ? Ref : never | undefined
requiredboolean | undefinedfalse
Whether the input is required.
size"xs" | "sm" | "md" | "lg" | "xl" | undefined
styleJSX.CSSProperties | undefined
stylesRadioGroupT.Styles | undefined
valuestring | undefined
The current value of the input (controlled).
variantRadioGroupItemVariant | undefined

Items#

A radio item object.
PropTypeDefaultDescription
descriptionJSX.Element
Description for the radio item.
disabledboolean | undefined
Whether the item is disabled.
labelJSX.Element
Label for the radio item.
valuestring | undefined
Value of the radio item.