# RadioGroup · HeroUI

> Radio group for selecting a single option from a list

- Page: https://jiguang132.com/systems/heroui/docs/components/radio-group
- Based on: HeroUI documentation (Apache-2.0) @ 60edd8ed751b1d2a270623fbb182bbcfa8baa9af

## Import

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

### Usage


> Example `radio-group-basic`: interactive preview on https://jiguang132.com/systems/heroui/docs/components/radio-group


### Anatomy

Import the RadioGroup component and access all parts using dot notation.

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

export default () => (
  <RadioGroup>
    <Label />
    <Description />
    <Radio value="option1">
      <Radio.Content> {/* The clickable area: control + label */}
        <Radio.Control>
          <Radio.Indicator>
            <span>✓</span> {/* Custom indicator (optional) */}
          </Radio.Indicator>
        </Radio.Control>
        Label {/* plain text — the clickable label */}
      </Radio.Content>
      <Description /> {/* Sibling — stays outside the button (announced via aria-describedby) */}
      <FieldError /> {/* Optional — per-radio validation message */}
    </Radio>
    <FieldError /> {/* Optional — group-level validation */}
  </RadioGroup>
)
```

### Custom Indicator


> Example `radio-group-custom-indicator`: interactive preview on https://jiguang132.com/systems/heroui/docs/components/radio-group


### Horizontal Orientation


> Example `radio-group-horizontal`: interactive preview on https://jiguang132.com/systems/heroui/docs/components/radio-group


### Controlled


> Example `radio-group-controlled`: interactive preview on https://jiguang132.com/systems/heroui/docs/components/radio-group


### Uncontrolled

Combine `defaultValue` with `onChange` when you only need to react to updates.


> Example `radio-group-uncontrolled`: interactive preview on https://jiguang132.com/systems/heroui/docs/components/radio-group


### Validation


> Example `radio-group-validation`: interactive preview on https://jiguang132.com/systems/heroui/docs/components/radio-group


### Disabled


> Example `radio-group-disabled`: interactive preview on https://jiguang132.com/systems/heroui/docs/components/radio-group


### Variants

The RadioGroup component supports two visual variants:

- **`primary`** (default) - Standard styling with default background, suitable for most use cases
- **`secondary`** - Lower emphasis variant, suitable for use in Surface components


> Example `radio-group-variants`: interactive preview on https://jiguang132.com/systems/heroui/docs/components/radio-group


### In Surface

When used inside a [Surface](/systems/heroui/docs/components/surface) component, use `variant="secondary"` to apply the lower emphasis variant suitable for surface backgrounds.


> Example `radio-group-on-surface`: interactive preview on https://jiguang132.com/systems/heroui/docs/components/radio-group


### Delivery & Payment


> Example `radio-group-delivery-and-payment`: interactive preview on https://jiguang132.com/systems/heroui/docs/components/radio-group


### Custom Render Function


> Example `radio-group-custom-render-function`: interactive preview on https://jiguang132.com/systems/heroui/docs/components/radio-group


## Styling

### Passing Tailwind CSS classes

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

export default () => (
  <RadioGroup defaultValue="premium" name="plan">
    <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.Indicator className="border-border border-2 group-hover:border-blue-400 group-data-[selected=true]:border-blue-500 group-data-[selected=true]:bg-blue-500" />
      Basic Plan
    </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.Indicator className="border-border border-2 group-hover:border-purple-400 group-data-[selected=true]:border-purple-500 group-data-[selected=true]:bg-purple-500" />
      Premium Plan
    </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.Indicator className="border-border border-2 group-hover:border-emerald-400 group-data-[selected=true]:border-emerald-500 group-data-[selected=true]:bg-emerald-500" />
      Business Plan
    </Radio>
  </RadioGroup>
);
```

### Customizing the component classes

To customize the RadioGroup component classes, you can use the `@layer components` directive.
  
[Learn more](https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes).

```css
@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](https://getbem.com/) 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](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/radio-group.css)):

#### Base Classes
- `.radio-group` - Base radio group container
- `.radio` - Individual radio item
- `.radio__content` - Radio button (RAC label wrapper for control + label text)
- `.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

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `value` | `string` | - | The current value (controlled) |
| `defaultValue` | `string` | - | The default value (uncontrolled) |
| `onChange` | `(value: string) => void` | - | Handler called when the value changes |
| `isDisabled` | `boolean` | `false` | Whether the radio group is disabled |
| `isRequired` | `boolean` | `false` | Whether the radio group is required |
| `isReadOnly` | `boolean` | `false` | Whether the radio group is read only |
| `isInvalid` | `boolean` | `false` | Whether the radio group is in an invalid state |
| `variant` | `"primary" \| "secondary"` | `"primary"` | Visual variant of the component. `primary` is the default style with shadow. `secondary` is a lower emphasis variant without shadow, suitable for use in surfaces. |
| `name` | `string` | - | The name of the radio group, used when submitting an HTML form |
| `orientation` | `'horizontal' \| 'vertical'` | `'vertical'` | The orientation of the radio group |
| `children` | `React.ReactNode \| (values: RadioGroupRenderProps) => React.ReactNode` | - | Radio group content or render prop |
| `render` | `DOMRenderFunction<keyof React.JSX.IntrinsicElements, RadioGroupRenderProps>` | - | Overrides the default DOM element with a custom render function.|

### Radio Props

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `value` | `string` | - | The value of the radio button |
| `isDisabled` | `boolean` | `false` | Whether the radio button is disabled |
| `name` | `string` | - | The name of the radio button, used when submitting an HTML form |
| `children` | `React.ReactNode \| (values: RadioFieldRenderProps) => React.ReactNode` | - | Radio content or field render prop |
| `render` | `DOMRenderFunction<keyof React.JSX.IntrinsicElements, RadioFieldRenderProps>` | - | Overrides the default DOM element with a custom render function.|

### Radio.Control Props

Extends `React.HTMLAttributes`.

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `children` | `React.ReactNode` | - | The content to render inside the control wrapper (typically Radio.Indicator) |

### Radio.Indicator Props

Extends `React.HTMLAttributes`.

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `children` | `React.ReactNode \| (values: RadioButtonRenderProps) => React.ReactNode` | - | Optional content or render prop that receives the current radio button state. |

### Radio.Content Props

The clickable area of the radio (the `<label>` wrapping the hidden input). Place `Radio.Control` and the `Label` inside it. `className` accepts a render function that receives `RadioButtonRenderProps`.

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `children` | `React.ReactNode \| (values: RadioButtonRenderProps) => React.ReactNode` | - | The clickable content (typically Radio.Control and Label) |

### RadioFieldRenderProps

When using a render prop on the root `Radio`, these field-level values are provided:

| Prop | Type | Description |
|------|------|-------------|
| `isSelected` | `boolean` | Whether the radio is currently selected |
| `isDisabled` | `boolean` | Whether the radio is disabled |
| `isReadOnly` | `boolean` | Whether the radio is read only |
| `isInvalid` | `boolean` | Whether the radio is in an invalid state |
| `isRequired` | `boolean` | Whether the radio is required |

### RadioButtonRenderProps

`Radio.Control` and `Radio.Indicator` use button-level render props (`isHovered`, `isPressed`, `isFocusVisible`, etc.). Pass a function as `Radio.Control` children or to `Radio.Indicator` to access them.

---

Index of all JGuang resources: https://jiguang132.com/llms.txt
