---
title: RadioGroup
description: A set of radio buttons where only one option can be selected at a time.
links:
  source_native: radio-group/radio-group.tsx
  styles_native: radio-group/radio-group.styles.ts
---

<NativeVideoPlayerView
  target="auto"
  srcLight="https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/docs/native/components/videos/radio-group-docs-light.mp4"
  srcDark="https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/docs/native/components/videos/radio-group-docs-dark.mp4"
/>

## Import

```tsx
import { RadioGroup } from 'heroui-native';
```

## Anatomy

```tsx
<RadioGroup>
  <RadioGroup.Item>
    <Label>...</Label>
    <Description>...</Description>
    <Radio>
      <Radio.Indicator>
        <Radio.IndicatorThumb />
      </Radio.Indicator>
    </Radio>
  </RadioGroup.Item>
  <FieldError>...</FieldError>
</RadioGroup>
```

- **RadioGroup**: Container that manages the selection state of radio items. Supports both horizontal and vertical orientations.
- **RadioGroup.Item**: Individual radio option within a RadioGroup. Must be used inside RadioGroup. Handles selection state and renders a default `<Radio />` indicator when text children are provided. Supports render function children to access state (`isSelected`, `isInvalid`, `isDisabled`).
- **Label**: Optional clickable text label for the radio option. Linked to the radio for accessibility. Use the [Label](./label) component directly.
- **Description**: Optional secondary text below the label. Provides additional context about the radio option. Use the [Description](./description) component directly.
- **Radio**: The [Radio](./radio) component used inside `RadioGroup.Item` to render the radio indicator. Automatically detects the `RadioGroupItem` context and derives `isSelected`, `isDisabled`, `isInvalid`, and `variant` from it.
- **Radio.Indicator**: Optional container for the radio circle. Renders default thumb if no children provided. Manages the visual selection state. See [Radio](./radio) for full API.
- **Radio.IndicatorBackground**: Optional theme-aware background container rendered behind the indicator content. Mounted automatically for the `secondary` variant while unselected and not invalid, when the active theme registers default background content (e.g. `glass`). Replace or remove it via the `background` prop on `Radio.Indicator`.
- **Radio.IndicatorThumb**: Optional inner circle that appears when selected. Animates scale based on selection. Can be replaced with custom content. See [Radio](./radio) for full API.
- **FieldError**: Error message displayed when radio group is invalid. Shown with animation below the radio group content. Use the [FieldError](./field-error) component directly.

## Usage

### Basic Usage

RadioGroup with simple string children automatically renders title and indicator.

```tsx
<RadioGroup value={value} onValueChange={setValue}>
  <RadioGroup.Item value="option1">Option 1</RadioGroup.Item>
  <RadioGroup.Item value="option2">Option 2</RadioGroup.Item>
  <RadioGroup.Item value="option3">Option 3</RadioGroup.Item>
</RadioGroup>
```

### With Descriptions

Add descriptive text below each radio option for additional context.

```tsx
import { RadioGroup, Radio, Label, Description } from 'heroui-native';
import { View } from 'react-native';

<RadioGroup value={value} onValueChange={setValue}>
  <RadioGroup.Item value="standard">
    <View>
      <Label>Standard Shipping</Label>
      <Description>Delivered in 5-7 business days</Description>
    </View>
    <Radio />
  </RadioGroup.Item>
  <RadioGroup.Item value="express">
    <View>
      <Label>Express Shipping</Label>
      <Description>Delivered in 2-3 business days</Description>
    </View>
    <Radio />
  </RadioGroup.Item>
</RadioGroup>;
```

### Custom Indicator

Replace the default indicator thumb with custom content using `Radio` sub-components.

```tsx
import { RadioGroup, Radio, Label } from 'heroui-native';

<RadioGroup value={value} onValueChange={setValue}>
  <RadioGroup.Item value="custom">
    {({ isSelected }) => (
      <>
        <Label>Custom Option</Label>
        <Radio>
          <Radio.Indicator>
            {isSelected && (
              <Animated.View entering={FadeIn}>
                <Icon name="check" size={12} />
              </Animated.View>
            )}
          </Radio.Indicator>
        </Radio>
      </>
    )}
  </RadioGroup.Item>
</RadioGroup>;
```

### With Render Function

Use a render function on RadioGroup.Item to access state and customize the entire content.

```tsx
import { RadioGroup, Radio, Label } from 'heroui-native';

<RadioGroup value={value} onValueChange={setValue}>
  <RadioGroup.Item value="option1">
    {({ isSelected, isInvalid, isDisabled }) => (
      <>
        <Label>Option 1</Label>
        <Radio>
          <Radio.Indicator>{isSelected && <CustomIcon />}</Radio.Indicator>
        </Radio>
      </>
    )}
  </RadioGroup.Item>
</RadioGroup>;
```

### With Error Message

Display validation errors below the radio group.

```tsx
import { RadioGroup, FieldError } from 'heroui-native';

function RadioGroupWithError() {
  const [value, setValue] = React.useState<string | undefined>(undefined);

  return (
    <RadioGroup value={value} onValueChange={setValue} isInvalid={!value}>
      <RadioGroup.Item value="agree">I agree to the terms</RadioGroup.Item>
      <RadioGroup.Item value="disagree">I do not agree</RadioGroup.Item>
      <FieldError isInvalid={!value}>
        Please select an option to continue
      </FieldError>
    </RadioGroup>
  );
}
```

## Example

```tsx
import {
  Description,
  Label,
  Radio,
  RadioGroup,
  Separator,
  Surface,
} from 'heroui-native';
import React from 'react';
import { View } from 'react-native';

export default function RadioGroupExample() {
  const [selection, setSelection] = React.useState('desc1');

  return (
    <Surface className="w-full">
      <RadioGroup value={selection} onValueChange={setSelection}>
        <RadioGroup.Item value="desc1">
          <View>
            <Label>Standard Shipping</Label>
            <Description>Delivered in 5-7 business days</Description>
          </View>
          <Radio />
        </RadioGroup.Item>
        <Separator className="my-1" />
        <RadioGroup.Item value="desc2">
          <View>
            <Label>Express Shipping</Label>
            <Description>Delivered in 2-3 business days</Description>
          </View>
          <Radio />
        </RadioGroup.Item>
        <Separator className="my-1" />
        <RadioGroup.Item value="desc3">
          <View>
            <Label>Overnight Shipping</Label>
            <Description>Delivered next business day</Description>
          </View>
          <Radio />
        </RadioGroup.Item>
      </RadioGroup>
    </Surface>
  );
}
```

You can find more examples in the [GitHub repository](<https://github.com/heroui-inc/heroui-native/blob/main/example/src/app/(home)/components/radio-group.tsx>).

## API Reference

### RadioGroup

| prop            | type                         | default     | description                                                                               |
| --------------- | ---------------------------- | ----------- | ----------------------------------------------------------------------------------------- |
| `children`      | `React.ReactNode`            | `undefined` | Radio group content                                                                       |
| `value`         | `string \| undefined`        | `undefined` | The currently selected value of the radio group                                           |
| `onValueChange` | `(val: string) => void`      | `undefined` | Callback fired when the selected value changes                                            |
| `isDisabled`    | `boolean`                    | `false`     | Whether the entire radio group is disabled                                                |
| `isInvalid`     | `boolean`                    | `false`     | Whether the radio group is invalid                                                        |
| `variant`       | `'primary' \| 'secondary'`   | `undefined` | Variant style for the radio group (inherited by items if not set on item)                 |
| `animation`     | `"disable-all" \| undefined` | `undefined` | Animation configuration. Use `"disable-all"` to disable all animations including children |
| `className`     | `string`                     | `undefined` | Custom class name                                                                         |
| `...ViewProps`  | `ViewProps`                  | -           | All standard React Native View props are supported                                        |

### RadioGroup.Item

| prop                | type                                                                         | default     | description                                                               |
| ------------------- | ---------------------------------------------------------------------------- | ----------- | ------------------------------------------------------------------------- |
| `children`          | `React.ReactNode \| ((props: RadioGroupItemRenderProps) => React.ReactNode)` | `undefined` | Radio item content or render function to customize the radio item         |
| `value`             | `string`                                                                     | `undefined` | The value associated with this radio item                                 |
| `isDisabled`        | `boolean`                                                                    | `false`     | Whether this specific radio item is disabled                              |
| `isInvalid`         | `boolean`                                                                    | `false`     | Whether the radio item is invalid                                         |
| `variant`           | `'primary' \| 'secondary'`                                                   | `'primary'` | Variant style for the radio item                                          |
| `hitSlop`           | `number`                                                                     | `6`         | Hit slop for the pressable area                                           |
| `className`         | `string`                                                                     | `undefined` | Custom class name                                                         |
| `...PressableProps` | `PressableProps`                                                             | -           | All standard React Native Pressable props are supported (except disabled) |

#### RadioGroupItemRenderProps

| prop         | type      | description                        |
| ------------ | --------- | ---------------------------------- |
| `isSelected` | `boolean` | Whether the radio item is selected |
| `isInvalid`  | `boolean` | Whether the radio item is invalid  |
| `isDisabled` | `boolean` | Whether the radio item is disabled |

### Radio (inside RadioGroup.Item)

The `Radio` component is used inside `RadioGroup.Item` to render the radio indicator. When placed inside a `RadioGroup.Item`, the Radio component automatically detects the `RadioGroupItem` context and derives `isSelected`, `isDisabled`, `isInvalid`, and `variant` from it — no manual prop passing is needed.

Use `<Radio />` for the default indicator, or compose with `Radio.Indicator` and `Radio.IndicatorThumb` for custom styling.

| prop                | type                                                                | default     | description                                                               |
| ------------------- | ------------------------------------------------------------------- | ----------- | ------------------------------------------------------------------------- |
| `children`          | `React.ReactNode \| ((props: RadioRenderProps) => React.ReactNode)` | `undefined` | Child elements or render function to customize the radio                  |
| `variant`           | `'primary' \| 'secondary'`                                          | `'primary'` | Variant style for the radio                                               |
| `isSelected`        | `boolean`                                                           | `undefined` | Whether the radio is currently selected                                   |
| `isDisabled`        | `boolean`                                                           | `undefined` | Whether the radio is disabled and cannot be interacted with               |
| `isInvalid`         | `boolean`                                                           | `false`     | Whether the radio is invalid (shows danger color)                         |
| `className`         | `string`                                                            | `undefined` | Additional CSS classes to apply                                           |
| `animation`         | `RadioRootAnimation`                                                | -           | Animation configuration for radio                                         |
| `onSelectedChange`  | `(isSelected: boolean) => void`                                     | `undefined` | Callback fired when the radio selection state changes                     |
| `...PressableProps` | `PressableProps`                                                    | -           | All standard React Native Pressable props are supported (except disabled) |

#### RadioRenderProps

| prop         | type      | description                   |
| ------------ | --------- | ----------------------------- |
| `isSelected` | `boolean` | Whether the radio is selected |
| `isDisabled` | `boolean` | Whether the radio is disabled |
| `isInvalid`  | `boolean` | Whether the radio is invalid  |

#### RadioRootAnimation

Animation configuration for radio root component. Can be:

- `"disable-all"`: Disable all animations including children (Indicator, IndicatorThumb)
- `undefined`: Use default animations

### Radio.Indicator

| prop                   | type                       | default     | description                                      |
| ---------------------- | -------------------------- | ----------- | ------------------------------------------------ |
| `children`             | `React.ReactNode`          | `undefined` | Content for the radio indicator                  |
| `className`            | `string`                   | `undefined` | Additional CSS classes for the indicator         |
| `background` | `React.ReactNode` | - | Background layer behind the indicator content. `undefined` renders the theme-aware default for the `secondary` variant while unselected and not invalid; custom node replaces it; `null` removes it |
| `...AnimatedViewProps` | `AnimatedProps<ViewProps>` | -           | All Reanimated Animated.View props are supported |

### Radio.IndicatorBackground

Absolute-fill container rendered behind the indicator content. With no children, the active library theme decides the default content (e.g. a glass blur layer); pass children to host custom content with the same positioning and clipping.

| prop           | type              | default | description                                    |
| -------------- | ----------------- | ------- | ---------------------------------------------- |
| `children`     | `React.ReactNode` | -       | Custom content inside the background container |
| `className`    | `string`          | -       | Additional CSS classes                         |
| `...ViewProps` | `ViewProps`       | -       | All standard View props are supported          |

### Radio.IndicatorThumb

| prop                    | type                           | default     | description                                                  |
| ----------------------- | ------------------------------ | ----------- | ------------------------------------------------------------ |
| `className`             | `string`                       | `undefined` | Additional CSS classes for the thumb                         |
| `animation`             | `RadioIndicatorThumbAnimation` | -           | Animation configuration for the thumb                        |
| `isAnimatedStyleActive` | `boolean`                      | `true`      | Whether animated styles (react-native-reanimated) are active |
| `...AnimatedViewProps`  | `AnimatedProps<ViewProps>`     | -           | All Reanimated Animated.View props are supported             |

#### RadioIndicatorThumbAnimation

Animation configuration for radio indicator thumb component. Can be:

- `false` or `"disabled"`: Disable all animations
- `true` or `undefined`: Use default animations
- `object`: Custom animation configuration

| prop                 | type                    | default                                              | description                                     |
| -------------------- | ----------------------- | ---------------------------------------------------- | ----------------------------------------------- |
| `state`              | `'disabled' \| boolean` | -                                                    | Disable animations while customizing properties |
| `scale.value`        | `[number, number]`      | `[1.5, 1]`                                           | Scale values [unselected, selected]             |
| `scale.timingConfig` | `WithTimingConfig`      | `{ duration: 300, easing: Easing.out(Easing.ease) }` | Animation timing configuration                  |

**Note:** For labels, descriptions, and error messages, use the base components directly:

- Use [Label](../label/label.md) component for labels
- Use [Description](../description/description.md) component for descriptions
- Use [FieldError](../field-error/field-error.md) component for error messages

## Hooks

### useRadioGroup

**Returns:**

| Property        | Type                       | Description                                    |
| --------------- | -------------------------- | ---------------------------------------------- |
| `value`         | `string \| undefined`      | Currently selected value                       |
| `isDisabled`    | `boolean`                  | Whether the radio group is disabled            |
| `isInvalid`     | `boolean`                  | Whether the radio group is in an invalid state |
| `variant`       | `'primary' \| 'secondary'` | Variant style for the radio group              |
| `onValueChange` | `(value: string) => void`  | Function to change the selected value          |

### useRadioGroupItem

**Returns:**

| Property           | Type                                           | Description                                                             |
| ------------------ | ---------------------------------------------- | ----------------------------------------------------------------------- |
| `isSelected`       | `boolean`                                      | Whether the radio item is selected                                      |
| `isDisabled`       | `boolean \| undefined`                         | Whether the radio item is disabled                                      |
| `isInvalid`        | `boolean \| undefined`                         | Whether the radio item is invalid                                       |
| `variant`          | `'primary' \| 'secondary' \| undefined`        | Variant style for the radio item                                        |
| `onSelectedChange` | `((isSelected: boolean) => void) \| undefined` | Callback to change the selection state (selects this item in the group) |
