Radio Group

Form

Radio button group for single-option selection.

Preview

Usage

example.jsx
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";

export default function Example() {
  return <RadioGroup />;
}

Source Code

Copy this file into components/ui/radio-group.jsx in your project.

radio-group.jsx
"use client";

import { forwardRef, createContext, useContext } from "react";
import { cn } from "@/lib/utils";

const RadioGroupContext = createContext({ value: "", onChange: () => {} });

const RadioGroup = forwardRef(
  ({ className, value, onValueChange, children, ...props }, ref) => {
    return (
      <RadioGroupContext.Provider value={{ value, onChange: onValueChange }}>
        <div ref={ref} role="radiogroup" className={cn("grid gap-2", className)} {...props}>
          {children}
        </div>
      </RadioGroupContext.Provider>
    );
  }
);
RadioGroup.displayName = "RadioGroup";

const RadioGroupItem = forwardRef(({ className, value: itemValue, ...props }, ref) => {
  const { value, onChange } = useContext(RadioGroupContext);
  const checked = value === itemValue;

  return (
    <button
      ref={ref}
      type="button"
      role="radio"
      aria-checked={checked}
      onClick={() => onChange?.(itemValue)}
      className={cn(
        "aspect-square h-4 w-4 rounded-full border border-primary shadow-sm",
        "focus:outline-none focus-visible:ring-1 focus-visible:ring-ring",
        "disabled:cursor-not-allowed disabled:opacity-50",
        "cursor-pointer",
        className
      )}
      {...props}
    >
      {checked && (
        <span className="flex items-center justify-center">
          <span className="h-2 w-2 rounded-full bg-primary" />
        </span>
      )}
    </button>
  );
});
RadioGroupItem.displayName = "RadioGroupItem";

export { RadioGroup, RadioGroupItem };

Quick Install

Make sure you have the cn() utility set up. It requires clsx and tailwind-merge.

npm install clsx tailwind-merge