MC Radio Group
A set of radio buttons for selecting one option from a group.
Overview
The mc-radio-group is a core form control of the MicroClub UI library. Built on the @base-ui/react radio group primitive, it provides accessible state handling and keyboard interactions while keeping MicroClub styling and theme tokens.
As a part of the MicroClub library, this component is designed for instant deployment into your codebase, giving you full ownership of its look and behavior.
Preview
import { McRadioGroup, McRadioGroupItem } from '../ui/mc-radio-group';export default function RadioGroupDemo() { return ( <McRadioGroup defaultValue="remember" className="w-fit"> <McRadioGroupItem value="remember" id="r1" text="Remember me" supportText="Save my login details for next time." /> </McRadioGroup> );}Add to Your Project
Deploy the mc-radio-group directly to your components/ui directory:
Manual Setup
If you prefer manual control:
'use client';import * as React from 'react';import { Radio as RadioPrimitive } from '@base-ui/react/radio';import { RadioGroup as RadioGroupPrimitive } from '@base-ui/react/radio-group';import { cva, type VariantProps } from 'class-variance-authority';import { cn } from '@/lib/utils';const radioGroupVariants = cva( 'peer relative flex shrink-0 items-center justify-center rounded-full border transition-colors outline-none disabled:cursor-not-allowed disabled:pointer-events-none disabled:opacity-50', { variants: { size: { sm: 'size-4 [&_[data-slot=radio-group-indicator]>span]:size-2', md: 'size-5 [&_[data-slot=radio-group-indicator]>span]:size-2.5', }, }, defaultVariants: { size: 'sm', }, });const radioGroupItemVariants = cva('inline-flex', { variants: { size: { sm: 'gap-2', md: 'gap-3', }, }, defaultVariants: { size: 'sm', },});const textVariants = cva('font-medium transition-colors', { variants: { size: { sm: 'text-sm', md: 'text-base', }, disabled: { true: 'text-muted-foreground', false: 'text-foreground', }, }, defaultVariants: { size: 'sm', disabled: false, },});const supportTextVariants = cva('font-regular', { variants: { size: { sm: 'text-sm', md: 'text-base', }, disabled: { true: 'text-muted-foreground', false: 'text-foreground', }, }, defaultVariants: { size: 'sm', disabled: false, },});function McRadioGroup({ className, ...props }: RadioGroupPrimitive.Props) { return ( <RadioGroupPrimitive data-slot="radio-group" className={cn('grid w-full gap-2', className)} {...props} /> );}export interface McRadioGroupItemProps extends RadioPrimitive.Root.Props, VariantProps<typeof radioGroupVariants> { text?: string; supportText?: string;}function McRadioGroupItem({ className, size = 'sm', text, supportText, id, disabled, value, ...props}: McRadioGroupItemProps) { const radioId = React.useId(); const finalId = id ?? radioId; const labelId = text ? `${finalId}-label` : undefined; const descriptionId = supportText ? `${finalId}-description` : undefined; return ( <label htmlFor={finalId} className={cn( radioGroupItemVariants({ size }), supportText ? 'items-start' : 'items-center', disabled ? 'cursor-not-allowed' : 'cursor-pointer', className )} > <RadioPrimitive.Root id={finalId} data-slot="radio-group-item" className={cn( radioGroupVariants({ size }), 'self-start mt-0.5', 'bg-primary-foreground border-muted-foreground', 'hover:border-primary', 'focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-ring', 'focus-within:outline-none focus-within:ring-4 focus-within:ring-ring', 'data-disabled:border-muted-foreground data-disabled:hover:border-muted-foreground', 'data-checked:border-primary' )} disabled={disabled} value={value} aria-labelledby={labelId} aria-describedby={descriptionId} {...props} > <RadioPrimitive.Indicator data-slot="radio-group-indicator" className="flex size-4 items-center justify-center" > <span className="absolute top-1/2 left-1/2 size-2 -translate-x-1/2 -translate-y-1/2 rounded-full bg-primary" /> </RadioPrimitive.Indicator> </RadioPrimitive.Root> {(text || supportText) && ( <span className={cn('flex flex-col', size === 'sm' ? 'gap-0' : 'gap-0.5')}> {text && ( <span id={labelId} className={textVariants({ size, disabled: !!disabled })}> {text} </span> )} {supportText && ( <span id={descriptionId} className={supportTextVariants({ size, disabled: !!disabled })} > {supportText} </span> )} </span> )} </label> );}export { McRadioGroup, McRadioGroupItem };Ensure your @/lib/utils or equivalent classname helper is correctly imported.
Usage
import { McRadioGroup, McRadioGroupItem } from '@/components/ui/mc-radio-group';
export default function Example() {
return (
<McRadioGroup defaultValue="remember">
<McRadioGroupItem
value="remember"
id="r1"
text="Remember me"
supportText="Save my login details for next time."
/>
</McRadioGroup>
);
}Examples
Sizes
<McRadioGroup defaultValue="sm">
<McRadioGroupItem value="sm" id="s1" size="sm" text="Remember me" />
<McRadioGroupItem value="md" id="s2" size="md" text="Remember me" />
</McRadioGroup>With Support Text
<McRadioGroup defaultValue="option1">
<McRadioGroupItem
value="option1"
id="r1"
text="Remember me"
supportText="Save my login details for next time."
/>
<McRadioGroupItem
value="option2"
id="r2"
text="Remember me"
supportText="Save my login details for next time."
/>
</McRadioGroup>States
<McRadioGroup defaultValue="checked">
<McRadioGroupItem value="unchecked" id="r1" text="Unchecked" />
<McRadioGroupItem value="checked" id="r2" text="Checked" />
<McRadioGroupItem value="disabled" id="r3" text="Disabled" disabled />
<McRadioGroupItem value="disabled-checked" id="r4" text="Disabled checked" disabled />
</McRadioGroup>Controlled
Manage the selected value programmatically with value and onValueChange.
import { useState } from 'react';
import { McRadioGroup, McRadioGroupItem } from '@/components/ui/mc-radio-group';
export default function Example() {
const [value, setValue] = useState('option1');
return (
<McRadioGroup value={value} onValueChange={setValue}>
<McRadioGroupItem value="option1" id="r1" text="Option 1" />
<McRadioGroupItem value="option2" id="r2" text="Option 2" />
<McRadioGroupItem value="option3" id="r3" text="Option 3" />
</McRadioGroup>
);
}API Reference
McRadioGroup Props
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | undefined | The controlled selected value |
onValueChange | (value: string) => void | undefined | Callback when selection changes |
defaultValue | string | undefined | The initial selected value |
disabled | boolean | false | Disables all radio items in the group |
className | string | undefined | Additional CSS classes for the group |
McRadioGroupItem Props
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | undefined | The value associated with this radio item |
size | "sm" | "md" | "sm" | The radio button size |
text | string | undefined | Main label displayed next to the radio button |
supportText | string | undefined | Secondary helper text under the main label |
disabled | boolean | false | Disables interactions and applies disabled styles |
id | string | undefined | Custom ID for the radio input |
className | string | undefined | Additional CSS classes for the radio root |
All other props from @base-ui/react/radio are supported.