- Accordion
- Alert
- Avatar
- Badge
- Breadcrumb
- Button
- Button Group
- Calendarnew
- Card
- Carousel
- Checkbox
- Chip
- Collapse
- Dialog
- Drawer
- Footer
- Gallery
- Icon Button
- Image
- Input
- List
- Mapnew
- Menu
- Navbar
- Pagination
- Popover
- Progress
- Radio
- Rating
- Select
- Sidebar
- Skeletonnew
- Slider
- Software Purchase Card
- Sonner / Toastnew
- Speed Dial
- Spinner
- Stepper
- Switch
- Table
- Tabs
- Textarea
- Timeline
- Tooltip
- Typography
- Video
import { Label } from "@/components/ui/label"
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"
export function RadioDemo() {
return (
<RadioGroup defaultValue="html">
<div className="flex items-center gap-2">
<RadioGroupItem value="html" id="html" />
<Label htmlFor="html" className="text-foreground cursor-pointer">
HTML
</Label>
</div>
<div className="flex items-center gap-2">
<RadioGroupItem value="react" id="react" />
<Label htmlFor="react" className="text-foreground cursor-pointer">
React
</Label>
</div>
</RadioGroup>
)
}
Installation
pnpm dlx @creative-tim/ui@latest add radio-group
Usage
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"<RadioGroup defaultValue="option1">
<RadioGroupItem value="option1" id="option1" />
<RadioGroupItem value="option2" id="option2" />
</RadioGroup>Examples
Radio Colors
Radio components with different color schemes (primary, secondary, info, success, warning, error) to visually distinguish between different options and provide visual variety.
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"
export function RadioColors() {
return (
<div className="flex flex-col gap-4">
<RadioGroup defaultValue="primary-1" className="flex flex-row gap-4">
<RadioGroupItem
value="primary-1"
className="border-primary/50 data-[state=checked]:border-primary data-[state=checked]:bg-primary/10 [&_[data-slot=radio-group-indicator]_svg]:fill-primary"
/>
<RadioGroupItem
value="primary-2"
className="border-primary/50 data-[state=checked]:border-primary data-[state=checked]:bg-primary/10 [&_[data-slot=radio-group-indicator]_svg]:fill-primary"
/>
</RadioGroup>
<RadioGroup defaultValue="secondary-1" className="flex flex-row gap-4">
<RadioGroupItem
value="secondary-1"
className="border-secondary/50 data-[state=checked]:border-secondary data-[state=checked]:bg-secondary/10 [&_[data-slot=radio-group-indicator]_svg]:fill-secondary"
/>
<RadioGroupItem
value="secondary-2"
className="border-secondary/50 data-[state=checked]:border-secondary data-[state=checked]:bg-secondary/10 [&_[data-slot=radio-group-indicator]_svg]:fill-secondary"
/>
</RadioGroup>
<RadioGroup defaultValue="info-1" className="flex flex-row gap-4">
<RadioGroupItem
value="info-1"
className="border-blue-500/50 data-[state=checked]:border-blue-500 data-[state=checked]:bg-blue-500/10 [&_[data-slot=radio-group-indicator]_svg]:fill-blue-500"
/>
<RadioGroupItem
value="info-2"
className="border-blue-500/50 data-[state=checked]:border-blue-500 data-[state=checked]:bg-blue-500/10 [&_[data-slot=radio-group-indicator]_svg]:fill-blue-500"
/>
</RadioGroup>
<RadioGroup defaultValue="success-1" className="flex flex-row gap-4">
<RadioGroupItem
value="success-1"
className="border-green-500/50 data-[state=checked]:border-green-500 data-[state=checked]:bg-green-500/10 [&_[data-slot=radio-group-indicator]_svg]:fill-green-500"
/>
<RadioGroupItem
value="success-2"
className="border-green-500/50 data-[state=checked]:border-green-500 data-[state=checked]:bg-green-500/10 [&_[data-slot=radio-group-indicator]_svg]:fill-green-500"
/>
</RadioGroup>
<RadioGroup defaultValue="warning-1" className="flex flex-row gap-4">
<RadioGroupItem
value="warning-1"
className="border-yellow-500/50 data-[state=checked]:border-yellow-500 data-[state=checked]:bg-yellow-500/10 [&_[data-slot=radio-group-indicator]_svg]:fill-yellow-500"
/>
<RadioGroupItem
value="warning-2"
className="border-yellow-500/50 data-[state=checked]:border-yellow-500 data-[state=checked]:bg-yellow-500/10 [&_[data-slot=radio-group-indicator]_svg]:fill-yellow-500"
/>
</RadioGroup>
<RadioGroup defaultValue="error-1" className="flex flex-row gap-4">
<RadioGroupItem
value="error-1"
className="border-destructive/50 data-[state=checked]:border-destructive data-[state=checked]:bg-destructive/10 [&_[data-slot=radio-group-indicator]_svg]:fill-destructive"
/>
<RadioGroupItem
value="error-2"
className="border-destructive/50 data-[state=checked]:border-destructive data-[state=checked]:bg-destructive/10 [&_[data-slot=radio-group-indicator]_svg]:fill-destructive"
/>
</RadioGroup>
</div>
)
}
Disabled Radio
A disabled radio group that cannot be interacted with, useful for displaying read-only options or temporarily restricting user interaction.
import { Label } from "@/components/ui/label"
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"
export function DisabledRadio() {
return (
<RadioGroup defaultValue="html">
<div className="flex items-center gap-2">
<RadioGroupItem value="html" id="html" disabled />
<Label htmlFor="html" className="text-foreground cursor-pointer">
HTML
</Label>
</div>
<div className="flex items-center gap-2">
<RadioGroupItem value="react" id="react" disabled />
<Label htmlFor="react" className="text-foreground cursor-pointer">
React
</Label>
</div>
</RadioGroup>
)
}
Radio with Description
A radio group component with labels and descriptive text that provides additional context and guidance to help users understand each option.
import { Label } from "@/components/ui/label"
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"
export function RadioWithDescription() {
return (
<RadioGroup defaultValue="html" className="gap-4">
<div className="flex gap-2">
<RadioGroupItem value="html" id="radio-description-html" />
<label
htmlFor="radio-description-html"
className="flex -translate-y-1 cursor-pointer flex-col items-start text-left"
>
<span className="font-semibold">HTML Version</span>
<span className="text-foreground text-sm">
Creative Tim UI HTML, packed with rich components and widgets.
</span>
</label>
</div>
<div className="flex gap-2">
<RadioGroupItem value="react" id="radio-description-react" />
<label
htmlFor="radio-description-react"
className="flex -translate-y-1 cursor-pointer flex-col items-start text-left"
>
<span className="font-semibold">React Version</span>
<span className="text-foreground text-sm">
Creative Tim UI React, packed with rich components and widgets.
</span>
</label>
</div>
</RadioGroup>
)
}
Radio with Link
A radio group component with labels that include clickable links, perfect for terms and conditions, privacy policies, or related documentation.
import { Label } from "@/components/ui/label"
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"
export function RadioWithLink() {
return (
<RadioGroup defaultValue="agree">
<div className="flex items-center gap-2">
<RadioGroupItem value="agree" id="radio-link-agree" />
<Label
htmlFor="radio-link-agree"
className="text-foreground flex cursor-pointer gap-1"
>
I agree with the{" "}
<a href="#" className="text-primary underline">
terms and conditions
</a>
</Label>
</div>
<div className="flex items-center gap-2">
<RadioGroupItem value="disagree" id="radio-link-disagree" />
<Label
htmlFor="radio-link-disagree"
className="text-foreground flex cursor-pointer gap-1"
>
I disagree with the{" "}
<a href="#" className="text-primary underline">
terms and conditions
</a>
</Label>
</div>
</RadioGroup>
)
}
Radio with Custom Icon
A radio group component with custom star icons that toggle between outlined and filled states, providing a more intuitive visual indicator for selected options.
"use client"
import * as React from "react"
import * as RadioGroupPrimitive from "@radix-ui/react-radio-group"
import { Star } from "lucide-react"
import { cn } from "@/lib/utils"
import { Label } from "@/components/ui/label"
import { RadioGroup } from "@/components/ui/radio-group"
export function RadioWithCustomIcon() {
return (
<RadioGroup defaultValue="html">
<div className="flex items-center gap-2">
<RadioGroupPrimitive.Item
value="html"
id="custom-icon-html"
className={cn(
"border-input text-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 group relative flex aspect-square size-5 shrink-0 items-center justify-center rounded-full border bg-transparent shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-transparent"
)}
>
<Star className="text-primary pointer-events-none absolute top-1/2 left-1/2 h-3 w-3 -translate-x-1/2 -translate-y-1/2 opacity-100 transition-opacity group-data-[state=checked]:opacity-0" />
<RadioGroupPrimitive.Indicator className="relative flex items-center justify-center">
<Star className="text-primary fill-primary absolute top-1/2 left-1/2 h-3 w-3 -translate-x-1/2 -translate-y-1/2" />
</RadioGroupPrimitive.Indicator>
</RadioGroupPrimitive.Item>
<Label
htmlFor="custom-icon-html"
className="text-foreground cursor-pointer"
>
HTML
</Label>
</div>
<div className="flex items-center gap-2">
<RadioGroupPrimitive.Item
value="react"
id="custom-icon-react"
className={cn(
"border-input text-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 group relative flex aspect-square size-5 shrink-0 items-center justify-center rounded-full border bg-transparent shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-transparent"
)}
>
<Star className="text-primary pointer-events-none absolute top-1/2 left-1/2 h-3 w-3 -translate-x-1/2 -translate-y-1/2 opacity-100 transition-opacity group-data-[state=checked]:opacity-0" />
<RadioGroupPrimitive.Indicator className="relative flex items-center justify-center">
<Star className="text-primary fill-primary absolute top-1/2 left-1/2 h-3 w-3 -translate-x-1/2 -translate-y-1/2" />
</RadioGroupPrimitive.Indicator>
</RadioGroupPrimitive.Item>
<Label
htmlFor="custom-icon-react"
className="text-foreground cursor-pointer"
>
React
</Label>
</div>
</RadioGroup>
)
}
Custom Radio
A radio group component with custom checkmark icons and rounded styling that demonstrates how to personalize the appearance to match your brand or design requirements.
"use client"
import * as React from "react"
import * as RadioGroupPrimitive from "@radix-ui/react-radio-group"
import { Check } from "lucide-react"
import { cn } from "@/lib/utils"
import { Label } from "@/components/ui/label"
import { RadioGroup } from "@/components/ui/radio-group"
export function CustomRadio() {
return (
<RadioGroup defaultValue="html">
<div className="flex items-center gap-2">
<RadioGroupPrimitive.Item
value="html"
id="custom-html"
className={cn(
"border-input text-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 aspect-square size-4 shrink-0 rounded border shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50"
)}
>
<RadioGroupPrimitive.Indicator className="relative flex items-center justify-center">
<Check className="h-4 w-4 stroke-2" />
</RadioGroupPrimitive.Indicator>
</RadioGroupPrimitive.Item>
<Label htmlFor="custom-html" className="text-foreground cursor-pointer">
HTML
</Label>
</div>
<div className="flex items-center gap-2">
<RadioGroupPrimitive.Item
value="react"
id="custom-react"
className={cn(
"border-input text-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 aspect-square size-4 shrink-0 rounded border shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50"
)}
>
<RadioGroupPrimitive.Indicator className="relative flex items-center justify-center">
<Check className="h-4 w-4 stroke-2" />
</RadioGroupPrimitive.Indicator>
</RadioGroupPrimitive.Item>
<Label
htmlFor="custom-react"
className="text-foreground cursor-pointer"
>
React
</Label>
</div>
</RadioGroup>
)
}
Props
The radio group component is built using Radix UI's RadioGroup primitive and accepts the following props:
RadioGroup (Root Component)
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | - | The controlled value of the selected radio item |
defaultValue | string | - | The value of the radio item to select by default (uncontrolled) |
onValueChange | (value: string) => void | - | Event handler called when the selected value changes |
disabled | boolean | false | When true, prevents the user from interacting with the radio group |
required | boolean | false | When true, indicates that a selection is required |
name | string | - | The name of the radio group when used in a form |
orientation | "horizontal" | "vertical" | "vertical" | The orientation of the radio group |
className | string | - | Additional CSS classes to apply to the radio group |
RadioGroupItem
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | - | A unique value for the item (required) |
disabled | boolean | false | When true, prevents the user from interacting with the item |
id | string | - | The id of the radio item for label association |
className | string | - | Additional CSS classes to apply to the item |
Accessibility
The radio group component follows accessibility best practices:
- Uses proper ARIA attributes for screen readers
- Supports keyboard navigation (Arrow keys to navigate, Space to select)
- Focus states are clearly visible for keyboard users
- Disabled state is properly communicated to assistive technologies
- Works with form labels using
htmlForandidattributes - Maintains proper semantic HTML structure
- Groups related radio items together for better screen reader navigation
Best Practices
- Use radio groups for mutually exclusive choices (only one option can be selected)
- Provide clear labels that describe each option
- Use descriptive text when options might not be immediately clear
- Consider using defaultValue for common or recommended selections
- Use disabled state to show unavailable options without hiding them
- Ensure sufficient contrast between selected and unselected states
- Test keyboard navigation and screen reader compatibility
- Group related radio items together for better organization
- Use horizontal layout when space is limited and options are short
- Use vertical layout for longer option labels or when space allows
The radio group component provides a clean and accessible way to create single-selection controls. It's ideal for forms, surveys, preference settings, and any interface where users need to choose one option from multiple alternatives.