Skip to content
Components

Radio Group

Selects exactly one choice from a visible set of options.

Playground

scheme

Applies a semantic color to the selected item.

defaultValue

Sets the initially selected density option.

disabled

Prevents selection changes for the whole group.

Usage

tsx
import { Label } from "earthling-ui/label";
import { RadioGroup, RadioGroupItem } from "earthling-ui/radio";

export function Example() {
  return (
    <>
      <RadioGroup defaultValue="email" aria-label="Notification method">
        <div>
          <RadioGroupItem id="email" value="email" />
          <Label htmlFor="email">Email</Label>
        </div>
        <div>
          <RadioGroupItem id="sms" value="sms" />
          <Label htmlFor="sms">Text message</Label>
        </div>
      </RadioGroup>
    </>
  );
}
  • Every RadioGroupItem needs a unique value and an associated label.
  • Use Radio Group when comparing all options is more useful than a Select menu.
  • Set a default only when one choice is safe to preselect.

Installation

Start with the project setup for React and Tailwind CSS 4. Both paths use the same component and theme.

bash
npm install earthling-ui

Use the component import shown above. Package updates keep the implementation current.

API reference

Declarations from the current library build, including inherited primitive props. Playground controls above show selected options; they are not the complete API.

tsx
// Generated by dts-bundle-generator v9.5.1

import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
import { VariantProps } from 'class-variance-authority';
import { ComponentPropsWithoutRef } from 'react';

export declare const radioGroupVariants: (props?: ({
	scheme?: "default" | "primary" | "secondary" | "tertiary" | "neutral" | "muted" | "good" | "caution" | "bad" | null | undefined;
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
export interface RadioGroupProps extends ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>, VariantProps<typeof radioGroupVariants> {
}
export declare const RadioGroup: import("react").ForwardRefExoticComponent<RadioGroupProps & import("react").RefAttributes<HTMLDivElement>>;
export declare const RadioGroupItem: import("react").ForwardRefExoticComponent<Omit<RadioGroupPrimitive.RadioGroupItemProps & import("react").RefAttributes<HTMLButtonElement>, "ref"> & import("react").RefAttributes<HTMLButtonElement>>;

export {};

Runtime dependencies: @radix-ui/react-radio-group, class-variance-authority, cnfast.

Source

Use the eject command to copy this implementation with its required helpers and project-specific imports.

View Radio Group implementation
tsx
"use client";

import {
  type ComponentPropsWithoutRef,
  type ComponentRef,
  forwardRef,
} from "react";
import * as RadioGroupPrimitive from "@radix-ui/react-radio-group";

import { cn } from "@/utils/cn";
import { schemes } from "@/utils/variants";
import { cva, type VariantProps } from "class-variance-authority";

const radioGroupVariants = cva("grid gap-2", {
  variants: {
    scheme: schemes,
  },
  defaultVariants: { scheme: "default" },
});

export interface RadioGroupProps
  extends
    ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>,
    VariantProps<typeof radioGroupVariants> {}

const RadioGroup = forwardRef<
  ComponentRef<typeof RadioGroupPrimitive.Root>,
  RadioGroupProps
>(({ className, scheme, ...props }, ref) => {
  return (
    <RadioGroupPrimitive.Root
      className={cn(radioGroupVariants({ scheme }), className)}
      {...props}
      ref={ref}
    />
  );
});
RadioGroup.displayName = RadioGroupPrimitive.Root.displayName;

const RadioGroupItem = forwardRef<
  ComponentRef<typeof RadioGroupPrimitive.Item>,
  ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>
>(({ className, ...props }, ref) => {
  return (
    <RadioGroupPrimitive.Item
      ref={ref}
      className={cn(
        "size-5 rounded-full border border-current/30 ring-offset-background focus:outline-none focus-visible:ring-2 focus-visible:ring-outline focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-bad aria-invalid:ring-bad/30 data-[state=checked]:border-transparent data-[state=checked]:bg-(--scheme-tint)",
        className,
      )}
      {...props}
    >
      <RadioGroupPrimitive.Indicator className="flex items-center justify-center">
        <i className="icon-[lucide--circle] h-2.5 w-2.5 fill-current text-(--scheme-foreground)" />
      </RadioGroupPrimitive.Indicator>
    </RadioGroupPrimitive.Item>
  );
});
RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName;

export { RadioGroup, RadioGroupItem, radioGroupVariants };