RadioGroupPreview

Radio group for selecting a single option from a list

Import

import { RadioGroup, Radio } from '@heroui/react';

Usage

Plan selectionChoose the plan that best suits your needs
"use client";

import {Description, Label, Radio, RadioGroup} from "@heroui/react";

export function Basic() {
  return (
    <RadioGroup defaultValue="premium" name="plan">
      <Label>Plan selection</Label>
      <Description>Choose the plan that best suits your needs</Description>
      <Radio value="basic">
        <Radio.Control>
          <Radio.Indicator />
        </Radio.Control>
        <Radio.Content>
          <Label>Basic Plan</Label>
          <Description>Includes 100 messages per month and up to 3 themes to set up</Description>
        </Radio.Content>
      </Radio>
      <Radio value="premium">
        <Radio.Control>
          <Radio.Indicator />
        </Radio.Control>
        <Radio.Content>
          <Label>Premium Plan</Label>
          <Description>Includes 200 messages per month and up to 6 themes to set up</Description>
        </Radio.Content>
      </Radio>
      <Radio value="business">
        <Radio.Control>
          <Radio.Indicator />
        </Radio.Control>
        <Radio.Content>
          <Label>Business Plan</Label>
          <Description>Unlimited messages and themes</Description>
        </Radio.Content>
      </Radio>
    </RadioGroup>
  );
}

Anatomy

Import all parts and piece them together.

import {RadioGroup, Radio, Label, Description} from '@heroui/react';

export default () => (
  <RadioGroup defaultValue="premium" name="plan">
    <Label>Plan selection</Label>
    <Description>Choose the plan that best suits your needs</Description>
    <Radio value="basic">
      <Radio.Control>
        <Radio.Indicator />
      </Radio.Control>
      <Radio.Content>
        <Label>Basic Plan</Label>
        <Description>Includes 100 messages per month and up to 3 themes to set up</Description>
      </Radio.Content>
    </Radio>
    <Radio value="premium">
      <Radio.Control>
        <Radio.Indicator />
      </Radio.Control>
      <Radio.Content>
        <Label>Premium Plan</Label>
        <Description>Includes 200 messages per month and up to 6 themes to set up</Description>
      </Radio.Content>
    </Radio>
    <Radio value="business">
      <Radio.Control>
        <Radio.Indicator />
      </Radio.Control>
      <Radio.Content>
        <Label>Business Plan</Label>
        <Description>Unlimited messages and themes</Description>
      </Radio.Content>
    </Radio>
  </RadioGroup>
);

Styling

Passing Tailwind CSS classes

import {RadioGroup, Radio, Label, Description} from '@heroui/react';

export default () => (
  <RadioGroup defaultValue="premium" name="plan">
    <Label>Plan selection</Label>
    <Description>Choose the plan that best suits your needs</Description>
    <Radio
      className="border-border group cursor-pointer rounded-xl border-2 p-4 hover:border-blue-300 data-[selected=true]:border-blue-500 data-[selected=true]:bg-blue-500/10"
      value="basic"
    >
      <Radio.Control className="border-border border-2 group-hover:border-blue-400 group-data-[selected=true]:border-blue-500 group-data-[selected=true]:bg-blue-500">
        <Radio.Indicator />
      </Radio.Control>
      <Radio.Content>
        <Label className="cursor-pointer font-semibold">Basic Plan</Label>
        <Description className="text-sm">
          Includes 100 messages per month and up to 3 themes to set up
        </Description>
      </Radio.Content>
    </Radio>
    <Radio
      className="border-border group cursor-pointer rounded-xl border-2 p-4 hover:border-purple-300 data-[selected=true]:border-purple-500 data-[selected=true]:bg-purple-500/10"
      value="premium"
    >
      <Radio.Control className="border-border border-2 group-hover:border-purple-400 group-data-[selected=true]:border-purple-500 group-data-[selected=true]:bg-purple-500">
        <Radio.Indicator />
      </Radio.Control>
      <Radio.Content>
        <Label className="cursor-pointer font-semibold">Premium Plan</Label>
        <Description className="text-sm">
          Includes 200 messages per month and up to 6 themes to set up
        </Description>
      </Radio.Content>
    </Radio>
    <Radio
      className="border-border group cursor-pointer rounded-xl border-2 p-4 hover:border-emerald-300 data-[selected=true]:border-emerald-500 data-[selected=true]:bg-emerald-500/10"
      value="business"
    >
      <Radio.Control className="border-border border-2 group-hover:border-emerald-400 group-data-[selected=true]:border-emerald-500 group-data-[selected=true]:bg-emerald-500">
        <Radio.Indicator />
      </Radio.Control>
      <Radio.Content>
        <Label className="cursor-pointer font-semibold">Business Plan</Label>
        <Description className="text-sm">Unlimited messages and themes</Description>
      </Radio.Content>
    </Radio>
  </RadioGroup>
);

Customizing the component classes

To customize the RadioGroup component classes, you can use the @layer components directive.
Learn more.

@layer components {
  .radio-group {
    @apply gap-2;
  }

  .radio {
    @apply gap-4 rounded-lg border border-border p-3 hover:bg-surface-hovered;
  }

  .radio__control {
    @apply border-2 border-primary;
  }

  .radio__indicator {
    @apply bg-primary;
  }

  .radio__content {
    @apply gap-1;
  }
}

HeroUI follows the BEM methodology to ensure component variants and states are reusable and easy to customize.

CSS Classes

The RadioGroup component uses these CSS classes (View source styles):

Base Classes

  • .radio-group - Base radio group container
  • .radio - Individual radio item
  • .radio__control - Radio control (circular button)
  • .radio__indicator - Radio indicator (inner dot)
  • .radio__content - Radio content wrapper

Modifier Classes

  • .radio--disabled - Disabled radio state

Interactive States

The radio supports both CSS pseudo-classes and data attributes for flexibility:

  • Selected: [aria-checked="true"] or [data-selected="true"] (indicator appears)
  • Hover: :hover or [data-hovered="true"] (border color changes)
  • Focus: :focus-visible or [data-focus-visible="true"] (shows focus ring)
  • Pressed: :active or [data-pressed="true"] (scale transform)
  • Disabled: :disabled or [aria-disabled="true"] (reduced opacity, no pointer events)
  • Invalid: [data-invalid="true"] or [aria-invalid="true"] (error border color)

API Reference

RadioGroup Props

PropTypeDefaultDescription
valuestring-The current value (controlled)
defaultValuestring-The default value (uncontrolled)
onChange(value: string) => void-Handler called when the value changes
isDisabledbooleanfalseWhether the radio group is disabled
isRequiredbooleanfalseWhether the radio group is required
isReadOnlybooleanfalseWhether the radio group is read only
isInvalidbooleanfalseWhether the radio group is in an invalid state
namestring-The name of the radio group, used when submitting an HTML form
orientation'horizontal' | 'vertical''vertical'The orientation of the radio group
childrenReact.ReactNode | (values: RadioGroupRenderProps) => React.ReactNode-Radio group content or render prop

Radio Props

PropTypeDefaultDescription
valuestring-The value of the radio button
isDisabledbooleanfalseWhether the radio button is disabled
namestring-The name of the radio button, used when submitting an HTML form
childrenReact.ReactNode | (values: RadioRenderProps) => React.ReactNode-Radio content or render prop

RadioRenderProps

When using the render prop pattern, these values are provided:

PropTypeDescription
isSelectedbooleanWhether the radio is currently selected
isHoveredbooleanWhether the radio is hovered
isPressedbooleanWhether the radio is currently pressed
isFocusedbooleanWhether the radio is focused
isFocusVisiblebooleanWhether the radio is keyboard focused
isDisabledbooleanWhether the radio is disabled
isReadOnlybooleanWhether the radio is read only
isInvalidbooleanWhether the radio is in an invalid state