Components

Radio Input

Allow users to select a single option from a set with accessible radio button inputs.

Controlled

Selected: option2

Select a plan

Sizes

Installation

Usage

import { RadioInput } from "@/registry/core/radio-input";

export default () => (
  <div>
    <RadioInput name="plan" label="Basic Plan" value="basic" />
    <RadioInput name="plan" label="Pro Plan" value="pro" />
    <RadioInput name="plan" label="Enterprise Plan" value="enterprise" />
  </div>
);

Examples

Sizes

<RadioInput size="sm" name="size" label="Small radio" value="sm" />
<RadioInput size="md" name="size" label="Medium radio" value="md" />

Without Label

<RadioInput name="option" value="1" />

Controlled

import { useState } from "react";

export default () => {
  const [selected, setSelected] = useState("option1");

  return (
    <div className="flex flex-col gap-3">
      <RadioInput
        name="controlled"
        label="Option 1"
        value="option1"
        checked={selected === "option1"}
        onChange={(e) => setSelected(e.target.value)}
      />
      <RadioInput
        name="controlled"
        label="Option 2"
        value="option2"
        checked={selected === "option2"}
        onChange={(e) => setSelected(e.target.value)}
      />
      <RadioInput
        name="controlled"
        label="Option 3"
        value="option3"
        checked={selected === "option3"}
        onChange={(e) => setSelected(e.target.value)}
      />
    </div>
  );
};

Disabled

<RadioInput name="plan" label="Disabled option" value="disabled" disabled />
<RadioInput name="plan" label="Disabled checked" value="checked" disabled checked />

Default Checked

<RadioInput name="plan" label="Basic Plan" value="basic" />
<RadioInput name="plan" label="Pro Plan" value="pro" defaultChecked />
<RadioInput name="plan" label="Enterprise Plan" value="enterprise" />

Radio Group

<fieldset>
  <legend className="text-sm font-medium mb-3">Select a plan</legend>
  <div className="flex flex-col gap-3">
    <RadioInput name="plan" label="Basic - $9/month" value="basic" />
    <RadioInput name="plan" label="Pro - $29/month" value="pro" />
    <RadioInput name="plan" label="Enterprise - $99/month" value="enterprise" />
  </div>
</fieldset>

API Reference

RadioInput

Extends input element props (excluding size).

PropTypeDefaultDescription
size'sm', 'md''sm'Radio button size
labelstring-Label text next to radio
namestring-Radio group name (required for grouping)
valuestring-Radio button value
idstring-Custom input ID (auto-generated if not provided)
disabledbooleanfalseDisable radio interaction
checkedboolean-Controlled checked state
defaultCheckedboolean-Uncontrolled default checked state
onChange(e: ChangeEvent) => void-Change event handler
classNamestring-Additional CSS classes for the label wrapper

Accessibility

  • Uses native <input type="radio"> with screen reader support
  • Automatically generates unique IDs if not provided
  • Label is properly associated with input via htmlFor
  • Radio buttons with the same name are automatically grouped
  • Keyboard accessible with arrow key navigation within groups
  • Focus ring provides clear visual feedback
  • Disabled state is communicated via aria-disabled on the label
  • Hover states are disabled when radio is disabled

Notes

  • The radio input uses sr-only to hide it visually while keeping it accessible
  • The inner dot appears only when radio is checked
  • Focus ring appears on keyboard focus with ring-4 style
  • Hover effects apply to both the radio and label for better UX
  • All radio buttons in a group must share the same name attribute
  • Only one radio in a group can be selected at a time
  • All standard input HTML attributes are supported (except size which is used for visual sizing)