# Radio Group (/components/forms/radio-group)

Use `RadioGroup` when someone must choose one value from a set of options. Pass a `label` to name
the group, then add a `RadioField` for each option.

apps/docs/src/examples/radio-group/basic.tsx

```tsx
import { RadioField, RadioGroup } from '@luke-ui/react/radio-group';

export default () => {
	return (
		<RadioGroup label="Text alignment" name="alignment">
			<RadioField label="Left" value="left" />
			<RadioField label="Centre" value="centre" />
			<RadioField label="Right" value="right" />
		</RadioGroup>
	);
};
```

## Options [#options]

Pass a `value` to each `RadioField`. Each option can have a `description` beneath its label. Use
`orientation="horizontal"` for a short set of options that fits in a row. The default orientation is
vertical, and a horizontal group wraps when it runs out of space.

apps/docs/src/examples/radio-group/orientations.tsx

```tsx
import { RadioField, RadioGroup } from '@luke-ui/react/radio-group';
import { Comparison, ComparisonItem } from '#docs';

export default () => {
	return (
		<Comparison>
			<ComparisonItem label="Vertical">
				<RadioGroup label="Text alignment">
					<RadioField label="Left" value="left" />
					<RadioField label="Centre" value="centre" />
					<RadioField label="Right" value="right" />
				</RadioGroup>
			</ComparisonItem>
			<ComparisonItem label="Horizontal">
				<RadioGroup label="Text alignment" orientation="horizontal">
					<RadioField label="Left" value="left" />
					<RadioField label="Centre" value="centre" />
					<RadioField label="Right" value="right" />
				</RadioGroup>
			</ComparisonItem>
		</Comparison>
	);
};
```

## Selection [#selection]

Use `defaultValue` for an uncontrolled initial choice. Pair `value` with `onChange` when application
state owns the choice. The selected option's `value` is submitted with the group's `name`.

apps/docs/src/examples/radio-group/controlled.tsx

```tsx
import { RadioField, RadioGroup } from '@luke-ui/react/radio-group';
import { Stack } from '@luke-ui/react/stack';
import { Text } from '@luke-ui/react/text';
import { useState } from 'react';

export default () => {
	const [alignment, setAlignment] = useState('left');

	return (
		<Stack gap="space.16">
			<RadioGroup label="Text alignment" onChange={setAlignment} value={alignment}>
				<RadioField label="Left" value="left" />
				<RadioField label="Centre" value="centre" />
				<RadioField label="Right" value="right" />
			</RadioGroup>
			<Text color="secondary" elementType="p" role="status">
				{`Selected alignment: ${alignment}`}
			</Text>
		</Stack>
	);
};
```

## Size [#size]

Set `size` on the group to size every option. Set it on a `RadioField` to override the group size.
The size does not change option label typography. When neither sets a size, the group inherits
`Form.controlSize` or uses `medium`.

apps/docs/src/examples/radio-group/sizes.tsx

```tsx
import { RadioField, RadioGroup } from '@luke-ui/react/radio-group';
import { Comparison, ComparisonItem } from '#docs';

export default () => {
	return (
		<Comparison>
			<ComparisonItem label="Small">
				<RadioGroup label="Text alignment" size="small">
					<RadioField label="Left" value="left" />
					<RadioField label="Right" value="right" />
				</RadioGroup>
			</ComparisonItem>
			<ComparisonItem label="Medium">
				<RadioGroup label="Text alignment" size="medium">
					<RadioField label="Left" value="left" />
					<RadioField label="Right" value="right" />
				</RadioGroup>
			</ComparisonItem>
		</Comparison>
	);
};
```

## Validation [#validation]

Set `isRequired` when the group needs a choice before the form submits. Pass `validate` for a custom
rule. Pass `errorMessage` for an error from a form library or server. A non-empty message marks the
group invalid and shows one message beneath its options. The group description remains visible when
the group is invalid. Read [Validation](/docs/validation) for where messages come from and how to
write them.

By default, a required group shows a marker after its label. Read
[Required fields](/docs/forms#required-fields) for the `necessityIndicator` values.

Submit without choosing an option to see the validation message.

apps/docs/src/examples/radio-group/validation.tsx

```tsx
import { Button } from '@luke-ui/react/button';
import { Cluster } from '@luke-ui/react/cluster';
import { RadioField, RadioGroup } from '@luke-ui/react/radio-group';
import { Stack } from '@luke-ui/react/stack';
import type { SubmitEvent } from 'react';

function handleSubmit(event: SubmitEvent<HTMLFormElement>) {
	event.preventDefault();
}

export default () => {
	return (
		<form onSubmit={handleSubmit}>
			<Stack gap="space.16">
				<RadioGroup isRequired label="Text alignment" name="alignment">
					<RadioField label="Left" value="left" />
					<RadioField label="Centre" value="centre" />
					<RadioField label="Right" value="right" />
				</RadioGroup>
				<Cluster>
					<Button type="submit">Submit</Button>
				</Cluster>
			</Stack>
		</form>
	);
};
```

## Accessibility [#accessibility]

Give the group a visible `label`, or use `aria-label` or `aria-labelledby` when another part of the
layout already names it. Use `RadioField` for each option so its visible label and optional
description stay connected to its radio control. The group supports arrow-key navigation. Disabled
groups keep their options disabled even if an individual option sets `isDisabled={false}`.

For a custom layout, compose the [Radio primitive](/components/primitives/radio).

## API [#api]

### RadioGroupProps [#radiogroupprops]

### RadioGroupProps

Props for `RadioGroup`.

`RadioGroupProps` also accepts compatible DOM and ARIA attributes and event handlers for its rendered element.

| Prop                  | Type                                                              | Description                                                                                                                                                                                                                               |
| --------------------- | ----------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `isRequired?`         | `boolean`                                                         | Whether user input is required on the input before form submission.                                                                                                                                                                       |
| `validate?`           | `(value: string) => true \| ValidationError \| null \| undefined` | A function that returns an error message if a given value is invalid. Validation errors are displayed to the user when the form is submitted if `validationBehavior="native"`. For realtime validation, use the `isInvalid` prop instead. |
| `isDisabled?`         | `boolean`                                                         | Whether the input is disabled.                                                                                                                                                                                                            |
| `defaultValue?`       | `string \| null`                                                  | The default value (uncontrolled).                                                                                                                                                                                                         |
| `onChange?`           | `(value: string) => void`                                         | Handler that is called when the value changes.                                                                                                                                                                                            |
| `aria-describedby?`   | `string`                                                          | Identifies the element (or elements) that describes the object.                                                                                                                                                                           |
| `aria-details?`       | `string`                                                          | Identifies the element (or elements) that provide a detailed, extended description for the object.                                                                                                                                        |
| `aria-errormessage?`  | `string`                                                          | Identifies the element that provides an error message for the object.                                                                                                                                                                     |
| `id?`                 | `string`                                                          | The element's unique identifier. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/id).                                                                                                                       |
| `name?`               | `string`                                                          | The name of the input element, used when submitting an HTML form. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdefname).                                                                             |
| `onFocus?`            | `(e: React.FocusEvent<Element, Element>) => void`                 | Handler that is called when the element receives focus.                                                                                                                                                                                   |
| `onBlur?`             | `(e: React.FocusEvent<Element, Element>) => void`                 | Handler that is called when the element loses focus.                                                                                                                                                                                      |
| `onFocusChange?`      | `(isFocused: boolean) => void`                                    | Handler that is called when the element's focus status changes.                                                                                                                                                                           |
| `validationBehavior?` | `'native' \| 'aria'`                                              | Whether to use native HTML form validation to prevent form submission when the value is missing or invalid, or mark the field as required or invalid via ARIA. Default: `'native'`                                                        |
| `description?`        | `ReactNode`                                                       | Optional helper text shown below the control.                                                                                                                                                                                             |
| `necessityIndicator?` | `NecessityIndicator`                                              | Controls how the label identifies required or optional values. Inherits from `Form`, or uses `'required-asterisk'` when unset.                                                                                                            |
| `label?`              | `Exclude<ReactNode, boolean \| null \| undefined>`                | Visible label. Pass non-empty, textual, non-interactive content. Place links and buttons outside it, and associate external label content with `aria-labelledby` instead.                                                                 |
| `aria-label?`         | `string`                                                          |                                                                                                                                                                                                                                           |
| `aria-labelledby?`    | `string`                                                          |                                                                                                                                                                                                                                           |
| `value?`              | `string \| null \| undefined`                                     | Selected option value when the group is controlled.                                                                                                                                                                                       |
| `ref?`                | `Ref<HTMLDivElement>`                                             | Forwarded to the group root element.                                                                                                                                                                                                      |
| `children`            | `ReactNode`                                                       | Radio options.                                                                                                                                                                                                                            |
| `errorMessage?`       | `ReactNode`                                                       | Validation message for a controlled error. A non-empty message marks the group invalid.                                                                                                                                                   |
| `className?`          | `ClassNameOrFunction<RadioGroupRenderProps> \| undefined`         | Class name for the group root.                                                                                                                                                                                                            |
| `orientation?`        | `Orientation \| undefined`                                        | The group layout and keyboard-navigation direction.                                                                                                                                                                                       |
| `size?`               | `ControlSize`                                                     | Visual size supplied to options that do not set their own size. Default: `'medium'`                                                                                                                                                       |

#### Type definitions

These are the types that this table's signatures and the definitions below name. TypeScript's built-in types, such as `Omit` and `ReadonlyArray`, are not listed.

##### `NecessityIndicator`

```ts
type NecessityIndicator = 'required-asterisk'
  | 'required-label'
  | 'optional-label';
```

##### `ControlSize`

```ts
type ControlSize = 'small' | 'medium';
```

##### `ValidationError`

Declared in [`@react-types/shared`](https://www.npmjs.com/package/@react-types/shared) (`src/inputs.d.ts`).

```ts
type ValidationError = string | string[];
```

##### `FocusEvent`

Declared in [`@types/react`](https://www.npmjs.com/package/@types/react) (`index.d.ts`).

##### `ReactNode`

Declared in [`@types/react`](https://www.npmjs.com/package/@types/react) (`index.d.ts`).

```ts
type ReactNode = ReactElement
  | string
  | number
  | bigint
  | Iterable<ReactNode>
  | ReactPortal
  | boolean
  | null
  | undefined
  | DO_NOT_USE_OR_YOU_WILL_BE_FIRED_EXPERIMENTAL_REACT_NODES[keyof DO_NOT_USE_OR_YOU_WILL_BE_FIRED_EXPERIMENTAL_REACT_NODES]
  | Promise<AwaitedReactNode>;
```

Refers to `ReactElement`, `ReactPortal`, `DO_NOT_USE_OR_YOU_WILL_BE_FIRED_EXPERIMENTAL_REACT_NODES`, and `AwaitedReactNode`.

##### `ReactElement`

Declared in [`@types/react`](https://www.npmjs.com/package/@types/react) (`index.d.ts`).

##### `ReactPortal`

Declared in [`@types/react`](https://www.npmjs.com/package/@types/react) (`index.d.ts`).

##### `DO_NOT_USE_OR_YOU_WILL_BE_FIRED_EXPERIMENTAL_REACT_NODES`

Declared in [`@types/react`](https://www.npmjs.com/package/@types/react) (`index.d.ts`).

##### `AwaitedReactNode`

Declared in [`@types/react`](https://www.npmjs.com/package/@types/react) (`index.d.ts`).

##### `Ref`

Declared in [`@types/react`](https://www.npmjs.com/package/@types/react) (`index.d.ts`).

```ts
type Ref<T> = RefCallback<T>
  | RefObject<T | null>
  | null;
```

Refers to `RefCallback` and `RefObject`.

##### `RefCallback`

Declared in [`@types/react`](https://www.npmjs.com/package/@types/react) (`index.d.ts`).

##### `RefObject`

Declared in [`@types/react`](https://www.npmjs.com/package/@types/react) (`index.d.ts`).

##### `ClassNameOrFunction`

Declared in [`react-aria-components`](https://www.npmjs.com/package/react-aria-components) (`dist/types/src/utils.d.ts`).

```ts
type ClassNameOrFunction<T> = string | ((values: T & {
  defaultClassName: string | undefined;
}) => string);
```

##### `RadioGroupRenderProps`

Declared in [`react-aria-components`](https://www.npmjs.com/package/react-aria-components) (`dist/types/src/RadioGroup.d.ts`).

##### `Orientation`

Declared in [`@react-types/shared`](https://www.npmjs.com/package/@react-types/shared) (`src/orientation.d.ts`).

```ts
type Orientation = 'horizontal' | 'vertical';
```

### RadioFieldProps [#radiofieldprops]

### RadioFieldProps

Props for `RadioField`.

`RadioFieldProps` also accepts compatible DOM and ARIA attributes and event handlers for its rendered element.

| Prop                | Type                                                      | Description                                                                                                             |
| ------------------- | --------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `aria-describedby?` | `string`                                                  | Identifies the element (or elements) that describes the object.                                                         |
| `aria-details?`     | `string`                                                  | Identifies the element (or elements) that provide a detailed, extended description for the object.                      |
| `onKeyDown?`        | `(e: KeyboardEvent) => void`                              | Handler that is called when a key is pressed.                                                                           |
| `onKeyUp?`          | `(e: KeyboardEvent) => void`                              | Handler that is called when a key is released.                                                                          |
| `onFocus?`          | `(e: React.FocusEvent<Element, Element>) => void`         | Handler that is called when the element receives focus.                                                                 |
| `onBlur?`           | `(e: React.FocusEvent<Element, Element>) => void`         | Handler that is called when the element loses focus.                                                                    |
| `onFocusChange?`    | `(isFocused: boolean) => void`                            | Handler that is called when the element's focus status changes.                                                         |
| `onPress?`          | `(e: PressEvent) => void`                                 | Handler that is called when the press is released over the target.                                                      |
| `onPressStart?`     | `(e: PressEvent) => void`                                 | Handler that is called when a press interaction starts.                                                                 |
| `onPressEnd?`       | `(e: PressEvent) => void`                                 | Handler that is called when a press interaction ends, either over the target or when the pointer leaves the target.     |
| `onPressChange?`    | `(isPressed: boolean) => void`                            | Handler that is called when the press state changes.                                                                    |
| `onPressUp?`        | `(e: PressEvent) => void`                                 | Handler that is called when a press is released over the target, regardless of whether it started on the target or not. |
| `autoFocus?`        | `boolean`                                                 | Whether the element should receive focus on render.                                                                     |
| `isDisabled?`       | `boolean`                                                 | Whether the radio button is disabled or not. Shows that a selection exists, but is not available in that circumstance.  |
| `className?`        | `ClassNameOrFunction<RadioFieldRenderProps> \| undefined` | Class name for the option root.                                                                                         |
| `value`             | `string`                                                  | Value submitted when this option is selected.                                                                           |
| `id?`               | `string`                                                  | Element id for the option root. Use `inputId` for the radio input.                                                      |
| `inputId?`          | `string \| undefined`                                     | Element id for the input.                                                                                               |
| `inputRef?`         | `React.Ref<HTMLInputElement \| null> \| undefined`        | Forwarded to the hidden radio input.                                                                                    |
| `ref?`              | `Ref<HTMLDivElement>`                                     | Forwarded to the option root element.                                                                                   |
| `size?`             | `"medium" \| "small" \| undefined`                        | Visual size of the radio option. Defaults to the group size, then `Form.controlSize`, then `medium`.                    |
| `description?`      | `ReactNode`                                               | Supporting text shown beneath the option label.                                                                         |
| `label`             | `Exclude<ReactNode, boolean \| null \| undefined>`        | Visible option label. Pass non-empty, textual, non-interactive content. Place links and buttons outside the label.      |

#### Type definitions

These are the types that this table's signatures and the definitions below name. TypeScript's built-in types, such as `Omit` and `ReadonlyArray`, are not listed.

##### `KeyboardEvent`

Declared in [`@react-types/shared`](https://www.npmjs.com/package/@react-types/shared) (`src/events.d.ts`).

```ts
type KeyboardEvent = BaseEvent<ReactKeyboardEvent<any>>;
```

Refers to `BaseEvent` and `KeyboardEvent` from `@types/react`.

##### `BaseEvent`

Declared in [`@react-types/shared`](https://www.npmjs.com/package/@react-types/shared) (`src/events.d.ts`).

##### `KeyboardEvent` from `@types/react` (written as `ReactKeyboardEvent`)

Declared in [`@types/react`](https://www.npmjs.com/package/@types/react) (`index.d.ts`).

##### `FocusEvent`

Declared in [`@types/react`](https://www.npmjs.com/package/@types/react) (`index.d.ts`).

##### `PressEvent`

Declared in [`@react-types/shared`](https://www.npmjs.com/package/@react-types/shared) (`src/events.d.ts`).

##### `ClassNameOrFunction`

Declared in [`react-aria-components`](https://www.npmjs.com/package/react-aria-components) (`dist/types/src/utils.d.ts`).

```ts
type ClassNameOrFunction<T> = string | ((values: T & {
  defaultClassName: string | undefined;
}) => string);
```

##### `RadioFieldRenderProps`

Declared in [`react-aria-components`](https://www.npmjs.com/package/react-aria-components) (`dist/types/src/RadioGroup.d.ts`).

##### `Ref`

Declared in [`@types/react`](https://www.npmjs.com/package/@types/react) (`index.d.ts`).

```ts
type Ref<T> = RefCallback<T>
  | RefObject<T | null>
  | null;
```

Refers to `RefCallback` and `RefObject`.

##### `RefCallback`

Declared in [`@types/react`](https://www.npmjs.com/package/@types/react) (`index.d.ts`).

##### `RefObject`

Declared in [`@types/react`](https://www.npmjs.com/package/@types/react) (`index.d.ts`).

##### `ReactNode`

Declared in [`@types/react`](https://www.npmjs.com/package/@types/react) (`index.d.ts`).

```ts
type ReactNode = ReactElement
  | string
  | number
  | bigint
  | Iterable<ReactNode>
  | ReactPortal
  | boolean
  | null
  | undefined
  | DO_NOT_USE_OR_YOU_WILL_BE_FIRED_EXPERIMENTAL_REACT_NODES[keyof DO_NOT_USE_OR_YOU_WILL_BE_FIRED_EXPERIMENTAL_REACT_NODES]
  | Promise<AwaitedReactNode>;
```

Refers to `ReactElement`, `ReactPortal`, `DO_NOT_USE_OR_YOU_WILL_BE_FIRED_EXPERIMENTAL_REACT_NODES`, and `AwaitedReactNode`.

##### `ReactElement`

Declared in [`@types/react`](https://www.npmjs.com/package/@types/react) (`index.d.ts`).

##### `ReactPortal`

Declared in [`@types/react`](https://www.npmjs.com/package/@types/react) (`index.d.ts`).

##### `DO_NOT_USE_OR_YOU_WILL_BE_FIRED_EXPERIMENTAL_REACT_NODES`

Declared in [`@types/react`](https://www.npmjs.com/package/@types/react) (`index.d.ts`).

##### `AwaitedReactNode`

Declared in [`@types/react`](https://www.npmjs.com/package/@types/react) (`index.d.ts`).
