---
title: ControlField
description: A field component that combines a label, description (or other content), and a control component (Switch or Checkbox) into a single pressable area.
links:
  source_native: control-field/control-field.tsx
  styles_native: control-field/control-field.styles.ts
---

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

## Import

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

## Anatomy

```tsx
<ControlField>
  <Label>...</Label>
  <Description>...</Description>
  <ControlField.Indicator>...</ControlField.Indicator>
  <FieldError>...</FieldError>
</ControlField>
```

- **ControlField**: Root container that manages layout and state propagation
- **Label**: Primary text label for the control (from [Label](./label) component)
- **Description**: Secondary descriptive helper text (from [Description](./description) component)
- **ControlField.Indicator**: Container for the form control component ([Switch](./switch), [Checkbox](./checkbox), [Radio](./radio))
- **FieldError**: Validation error message display (from [FieldError](./field-error) component)

## Usage

### Basic Usage

ControlField wraps form controls to provide consistent layout and state management.

```tsx
<ControlField isSelected={value} onSelectedChange={setValue}>
  <Label className="flex-1">Label text</Label>
  <ControlField.Indicator />
</ControlField>
```

### With Description

Add helper text below the label using the Description component.

```tsx
<ControlField isSelected={value} onSelectedChange={setValue}>
  <View className="flex-1">
    <Label>Enable notifications</Label>
    <Description>
      Receive push notifications about your account activity
    </Description>
  </View>
  <ControlField.Indicator />
</ControlField>
```

### With Error Message

Display validation errors using the ErrorMessage component.

```tsx
<ControlField
  isSelected={value}
  onSelectedChange={setValue}
  isInvalid={!value}
  className="flex-col items-start gap-1"
>
  <View className="flex-row items-center gap-2">
    <View className="flex-1">
      <Label>I agree to the terms</Label>
      <Description>
        By checking this box, you agree to our Terms of Service
      </Description>
    </View>
    <ControlField.Indicator variant="checkbox" />
  </View>
  <FieldError>This field is required</FieldError>
</ControlField>
```

### Disabled State

Control interactivity with the disabled prop.

```tsx
<ControlField isSelected={value} onSelectedChange={setValue} isDisabled>
  <View className="flex-1">
    <Label>Disabled field</Label>
    <Description>This field is disabled</Description>
  </View>
  <ControlField.Indicator />
</ControlField>
```

### Disabling All Animations

Disable all animations including children by using `"disable-all"`. This cascades down to all child components.

```tsx
<ControlField
  isSelected={value}
  onSelectedChange={setValue}
  animation="disable-all"
>
  <View className="flex-1">
    <Label>Label text</Label>
    <Description>Description text</Description>
  </View>
  <ControlField.Indicator />
</ControlField>
```

## Example

```tsx
import {
  Checkbox,
  Description,
  FieldError,
  ControlField,
  Label,
  Switch,
} from 'heroui-native';
import React from 'react';
import { ScrollView, View } from 'react-native';

export default function ControlFieldExample() {
  const [notifications, setNotifications] = React.useState(false);
  const [terms, setTerms] = React.useState(false);
  const [newsletter, setNewsletter] = React.useState(true);

  return (
    <ScrollView className="bg-background p-4">
      <View className="gap-4">
        <ControlField
          isSelected={notifications}
          onSelectedChange={setNotifications}
        >
          <View className="flex-1">
            <Label>Enable notifications</Label>
            <Description>
              Receive push notifications about your account activity
            </Description>
          </View>
          <ControlField.Indicator />
        </ControlField>

        <ControlField
          isSelected={terms}
          onSelectedChange={setTerms}
          isInvalid={!terms}
          className="flex-col items-start gap-1"
        >
          <View className="flex-row items-center gap-2">
            <View className="flex-1">
              <Label>I agree to the terms and conditions</Label>
              <Description>
                By checking this box, you agree to our Terms of Service
              </Description>
            </View>
            <ControlField.Indicator className="mt-0.5">
              <Checkbox />
            </ControlField.Indicator>
          </View>
          <FieldError>This field is required</FieldError>
        </ControlField>

        <ControlField isSelected={newsletter} onSelectedChange={setNewsletter}>
          <View className="flex-1">
            <Label>Subscribe to newsletter</Label>
          </View>
          <ControlField.Indicator>
            <Checkbox color="warning" />
          </ControlField.Indicator>
        </ControlField>
      </View>
    </ScrollView>
  );
}
```

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

## API Reference

### ControlField

| prop              | type                                                                       | default     | description                                                                               |
| ----------------- | -------------------------------------------------------------------------- | ----------- | ----------------------------------------------------------------------------------------- |
| children          | `React.ReactNode \| ((props: ControlFieldRenderProps) => React.ReactNode)` | -           | Content to render inside the form control, or a render function                           |
| isSelected        | `boolean`                                                                  | `undefined` | Whether the control is selected/checked                                                   |
| isDisabled        | `boolean`                                                                  | `false`     | Whether the form control is disabled                                                      |
| isInvalid         | `boolean`                                                                  | `false`     | Whether the form control is invalid                                                       |
| isRequired        | `boolean`                                                                  | `false`     | Whether the form control is required                                                      |
| className         | `string`                                                                   | -           | Custom class name for the root element                                                    |
| onSelectedChange  | `(isSelected: boolean) => void`                                            | -           | Callback when selection state changes                                                     |
| animation         | `"disable-all" \| undefined`                                               | `undefined` | Animation configuration. Use `"disable-all"` to disable all animations including children |
| ...PressableProps | `PressableProps`                                                           | -           | All React Native Pressable props are supported                                            |

### Label

The `Label` component automatically consumes form state (`isDisabled`, `isInvalid`) from the ControlField context.

**Note**: For complete prop documentation, see the [Label component documentation](./label).

### Description

The `Description` component automatically consumes form state (`isDisabled`, `isInvalid`) from the ControlField context.

**Note**: For complete prop documentation, see the [Description component documentation](./description).

### ControlField.Indicator

| prop         | type                                | default    | description                                                |
| ------------ | ----------------------------------- | ---------- | ---------------------------------------------------------- |
| children     | `React.ReactNode`                   | -          | Control component to render (Switch, Checkbox, Radio)      |
| variant      | `'checkbox' \| 'radio' \| 'switch'` | `'switch'` | Variant of the control to render when no children provided |
| className    | `string`                            | -          | Custom class name for the indicator element                |
| ...ViewProps | `ViewProps`                         | -          | All React Native View props are supported                  |

**Note**: When children are provided, the component automatically passes down `isSelected`, `onSelectedChange`, `isDisabled`, and `isInvalid` props from the ControlField context if they are not already present on the child component. When using the `radio` variant, the Radio component renders in standalone mode (outside of a RadioGroup).

### FieldError

The `FieldError` component automatically consumes form state (`isInvalid`) from the ControlField context.

**Note**: For complete prop documentation, see the [FieldError component documentation](./field-error). The error message visibility is controlled by the `isInvalid` state of the parent ControlField.

## Hooks

### useControlField

**Returns:**

| property           | type                                           | description                                    |
| ------------------ | ---------------------------------------------- | ---------------------------------------------- |
| `isSelected`       | `boolean \| undefined`                         | Whether the control is selected/checked        |
| `onSelectedChange` | `((isSelected: boolean) => void) \| undefined` | Callback when selection state changes          |
| `isDisabled`       | `boolean`                                      | Whether the form control is disabled           |
| `isInvalid`        | `boolean`                                      | Whether the form control is invalid            |
| `isPressed`        | `SharedValue<boolean>`                         | Reanimated shared value indicating press state |
