Octocat

Radio

A radio button input component.

import { Label } from '@/components/label';
import { Radio } from '@/components/radio';

export default function RadioPreview() {
  return (
    <div className="flex flex-col gap-4">
      <div className="space-y-2">
        <div className="flex items-center gap-2">
          <Radio id="option1" name="options" />
          <Label htmlFor="option1">Option 1</Label>
        </div>
        <div className="flex items-center gap-2">
          <Radio id="option2" name="options" />
          <Label htmlFor="option2">Option 2</Label>
        </div>
        <div className="flex items-center gap-2">
          <Radio id="option3" name="options" />
          <Label htmlFor="option3">Option 3</Label>
        </div>
      </div>

      <div className="space-y-2">
        <div className="flex items-center gap-2">
          <Radio id="disabled" disabled />
          <Label htmlFor="disabled">Disabled</Label>
        </div>
        <div className="flex items-center gap-2">
          <Radio id="checked-disabled" disabled defaultChecked />
          <Label htmlFor="checked-disabled">Checked & Disabled</Label>
        </div>
      </div>
    </div>
  );
}

Source Code

import { cva } from '@/lib/utils/classnames';

const radioStyle = cva({
  base: [
    'relative flex size-5 shrink-0 appearance-none items-center justify-center rounded-full border border-border bg-background shadow-xs outline-none ring-ring transition focus-visible:ring-4 enabled:cursor-pointer enabled:not-checked:hover:border-mix-border/8',
    // checked
    'checked:enabled:hover:mix-with-accent-foreground checked:enabled:border-accent checked:enabled:bg-accent checked:enabled:hover:border-mix-accent/8',
    // checked circle
    'checked:before:absolute checked:before:h-1.5 checked:before:w-1.5 checked:before:rounded-full checked:before:bg-accent-foreground',
    // disabled
    'disabled:cursor-not-allowed disabled:border-foreground/5 disabled:bg-foreground/10 disabled:checked:before:bg-foreground/50',
  ],
});

const Radio = ({
  className,
  ...props
}: Omit<React.ComponentPropsWithRef<'input'>, 'type'>) => {
  return (
    <input type="radio" className={radioStyle({ className })} {...props} />
  );
};

export { Radio };

API Reference

Extends the input element with type="radio".

Examples

Simple

Basic usage of radio buttons.

import { Label } from '@/components/label';
import { Radio } from '@/components/radio';

export default function RadioPreview() {
  return (
    <div className="flex flex-col gap-4">
      <div className="space-y-2">
        <div className="flex items-center gap-2">
          <Radio id="option1" name="options" />
          <Label htmlFor="option1">Option 1</Label>
        </div>
        <div className="flex items-center gap-2">
          <Radio id="option2" name="options" />
          <Label htmlFor="option2">Option 2</Label>
        </div>
        <div className="flex items-center gap-2">
          <Radio id="option3" name="options" />
          <Label htmlFor="option3">Option 3</Label>
        </div>
      </div>

      <div className="space-y-2">
        <div className="flex items-center gap-2">
          <Radio id="disabled" disabled />
          <Label htmlFor="disabled">Disabled</Label>
        </div>
        <div className="flex items-center gap-2">
          <Radio id="checked-disabled" disabled defaultChecked />
          <Label htmlFor="checked-disabled">Checked & Disabled</Label>
        </div>
      </div>
    </div>
  );
}

Best Practices

  1. Labels:

    • Use clear, concise labels
    • Make labels clickable
    • Consider label position
  2. Accessibility:

    • Ensure keyboard navigation
    • Use fieldset and legend for groups
    • Maintain sufficient spacing between options

Previous

Portal

Next

Select