---
title: Field
description: Lays out a form control with its label, description and error message, so inputs, selects and checkboxes line up and announce errors accessibly.
icon: rectangle-ellipsis
author:
  name: shadcn
  url: https://github.com/shadcn
search:
  keywords: [form field, label and error]
related:
  - /form
  - /input
  - /label
mode: wide
---

<PoweredBy packages={[{ name: 'Shadcn UI', url: 'https://ui.shadcn.com/docs/components/field' }]} />

### Installation

```package-install
npx shadcn@latest add @redpanda/field
```

<ComponentPreview name="field-demo" />

## When to use

Use this decision tree to determine when to use the Field component:

```mermaid
graph TD;
    A[❓ Need form control?] -->|Yes| B{Display content only?};
    A -->|No| C[ℹ️ Use plain input/select];
    B -->|Yes| D[ℹ️ Use Item component];
    B -->|No| E{Need label/description?};
    E -->|Yes| F[✅ Use Field];
    F --> G{Multiple related fields?};
    G -->|Yes| H[✅ Wrap with FieldGroup];
    G -->|No| I[✅ Single Field];
    F --> J{Validation errors?};
    J -->|Yes| K[✅ Add FieldError component];
    F --> L{Group semantic fields?};
    L -->|Yes| M[✅ Use FieldSet + FieldLegend];

    classDef recommended fill:#4ade80,stroke:#22c55e,stroke-width:2px,color:#000;
    classDef discouraged fill:#fbbf24,stroke:#f59e0b,stroke-width:2px,color:#000;
    classDef decision fill:#60a5fa,stroke:#3b82f6,stroke-width:2px,color:#fff;
    classDef neutral fill:#9ca3af,stroke:#6b7280,stroke-width:2px,color:#fff;

    class F,H,I,K,M recommended;
    class D discouraged;
    class A,B,E,G,J,L decision;
    class C neutral;
```

## Usage

```tsx lineNumbers
import {
  Field,
  FieldContent,
  FieldDescription,
  FieldError,
  FieldGroup,
  FieldLabel,
  FieldLegend,
  FieldSeparator,
  FieldSet,
  FieldTitle,
} from '@/components/ui/field';
```

```tsx lineNumbers
<FieldSet>
  <FieldLegend>Profile</FieldLegend>
  <FieldDescription>This appears on invoices and emails.</FieldDescription>
  <FieldGroup>
    <Field>
      <FieldLabel htmlFor="name">Full name</FieldLabel>
      <Input id="name" autoComplete="off" placeholder="Evil Rabbit" />
      <FieldDescription>This appears on invoices and emails.</FieldDescription>
    </Field>
    <Field>
      <FieldLabel htmlFor="username">Username</FieldLabel>
      <Input id="username" autoComplete="off" aria-invalid />
      <FieldError>Choose another username.</FieldError>
    </Field>
    <Field orientation="horizontal">
      <Switch id="newsletter" />
      <FieldLabel htmlFor="newsletter">Subscribe to the newsletter</FieldLabel>
    </Field>
  </FieldGroup>
</FieldSet>
```

## Anatomy

The `Field` family is designed for composing accessible forms. Here's how the components work together:

```tsx
<FieldSet>
  {' '}
  {/* Semantic fieldset container */}
  <FieldLegend /> {/* Fieldset legend/title */}
  <FieldDescription /> {/* Optional fieldset description */}
  <FieldGroup>
    {' '}
    {/* Groups multiple fields */}
    <Field>
      {' '}
      {/* Individual field wrapper */}
      <FieldLabel /> {/* Field label */}
      {/* Control: Input, Select, Switch, etc. */}
      <FieldDescription /> {/* Field-level helper text */}
      <FieldError /> {/* Validation error message */}
    </Field>
    <FieldSeparator /> {/* Optional visual divider */}
    <Field /> {/* Another field */}
  </FieldGroup>
</FieldSet>
```

### Layout Structure

- **FieldSet**: Semantic `<fieldset>` container for grouping related fields
- **FieldLegend**: Title for the fieldset (supports `legend` and `label` variants)
- **FieldGroup**: Layout wrapper that stacks fields with container query support
- **Field**: Core wrapper for a single field with orientation control
- **FieldLabel**: Label styled for inputs (use `htmlFor` for proper association)
- **FieldTitle**: Alternative to FieldLabel when no input association is needed
- **FieldContent**: Groups label and description for horizontal layouts
- **FieldDescription**: Helper text providing context or instructions
- **FieldError**: Accessible error container supporting react-hook-form errors
- **FieldSeparator**: Visual divider between fields

### Orientation Modes

Fields support three orientation modes via the `orientation` prop:

- **vertical** (default): Stacks label, control, and helper text
- **horizontal**: Aligns label and control side-by-side
- **responsive**: Switches between vertical and horizontal based on container size

### Typical Usage Patterns

```tsx
// Simple vertical field
<Field>
  <FieldLabel htmlFor="email">Email</FieldLabel>
  <Input id="email" type="email" />
  <FieldDescription>We'll never share your email.</FieldDescription>
</Field>

// Horizontal field with content wrapper
<Field orientation="horizontal">
  <Switch id="notifications" />
  <FieldContent>
    <FieldLabel htmlFor="notifications">Enable notifications</FieldLabel>
    <FieldDescription>Receive updates via email.</FieldDescription>
  </FieldContent>
</Field>

// Field with validation error
<Field data-invalid>
  <FieldLabel htmlFor="username">Username</FieldLabel>
  <Input id="username" aria-invalid />
  <FieldError>Username is already taken.</FieldError>
</Field>

// Multiple fields in a group
<FieldSet>
  <FieldLegend>Account Settings</FieldLegend>
  <FieldGroup>
    <Field>
      <FieldLabel htmlFor="name">Name</FieldLabel>
      <Input id="name" />
    </Field>
    <FieldSeparator />
    <Field>
      <FieldLabel htmlFor="bio">Bio</FieldLabel>
      <Textarea id="bio" />
    </Field>
  </FieldGroup>
</FieldSet>
```

## Form

We exclusively use `react-hook-form` library with `zod` validation schema. For further information, you can check out shadcn's official docs [here](https://ui.shadcn.com/docs/forms/react-hook-form)

## Examples

### Input

<ComponentPreview name="field-input-demo" />

### Textarea

<ComponentPreview name="field-textarea-demo" />

### Select

<ComponentPreview name="field-select-demo" />

### Slider

<ComponentPreview name="field-slider-demo" />

### Fieldset

<ComponentPreview name="field-fieldset-demo" />

### Checkbox

<ComponentPreview name="field-checkbox-demo" />

### Radio

<ComponentPreview name="field-radio-demo" />

### Switch

<ComponentPreview name="field-switch-demo" />

### Choice Card

Wrap `Field` components inside `FieldLabel` to create selectable field groups. This works with `RadioItem`, `Checkbox` and `Switch` components.

The former [Choicebox](/docs/choicebox) API has been removed. Use this explicit Field and Radio Group composition instead.

<ComponentPreview name="field-choice-card-demo" />

### Field Group

Stack `Field` components with `FieldGroup`. Add `FieldSeparator` to divide them.

<ComponentPreview name="field-field-group-demo" />

## Responsive Layout

- **Vertical fields:** Default orientation stacks label, control, and helper text—ideal for mobile-first layouts.
- **Horizontal fields:** Set `orientation="horizontal"` on `Field` to align the label and control side-by-side. Pair with `FieldContent` to keep descriptions aligned.
- **Responsive fields:** Set `orientation="responsive"` for automatic column layouts inside container-aware parents. Apply `@container/field-group` classes on `FieldGroup` to switch orientations at specific breakpoints.

## Validation and Errors

- Add `data-invalid` to `Field` to switch the entire block into an error state.
- Add `aria-invalid` on the input itself for assistive technologies.
- Render `FieldError` immediately after the control or inside `FieldContent` to keep error messages aligned with the field.

```tsx lineNumbers
// [!code word:data-invalid]
// [!code word:aria-invalid]
<Field data-invalid>
  <FieldLabel htmlFor="email">Email</FieldLabel>
  <Input id="email" type="email" aria-invalid />
  <FieldError>Enter a valid email address.</FieldError>
</Field>
```

## Accessibility

- `FieldSet` and `FieldLegend` keep related controls grouped for keyboard and assistive tech users.
- `Field` is a layout container, not a semantic group. Use `FieldSet` with `FieldLegend` to name a group of related controls. Associate each `FieldLabel` explicitly through `htmlFor` and the control's `id`, or wrap its control in the label.
- Apply `FieldSeparator` sparingly to ensure screen readers encounter clear section boundaries.

## API Reference

### FieldSet

Container that renders a semantic `fieldset` with spacing presets.

| Prop        | Type     | Default |
| ----------- | -------- | ------- |
| `className` | `string` |         |

```tsx
<FieldSet>
  <FieldLegend>Delivery</FieldLegend>
  <FieldGroup>{/* Fields */}</FieldGroup>
</FieldSet>
```

### FieldLegend

Legend element for a `FieldSet`. Switch to the `label` variant to align with label sizing.

| Prop        | Type                  | Default    |
| ----------- | --------------------- | ---------- |
| `variant`   | `"legend" \| "label"` | `"legend"` |
| `className` | `string`              |            |

```tsx
<FieldLegend variant="label">Notification Preferences</FieldLegend>
```

The `FieldLegend` has two variants: `legend` and `label`. The `label` variant applies label sizing and alignment. Handy if you have nested `FieldSet`.

### FieldGroup

Layout wrapper that stacks `Field` components and enables container queries for responsive orientations.

| Prop        | Type     | Default |
| ----------- | -------- | ------- |
| `className` | `string` |         |

```tsx
<FieldGroup className="@container/field-group flex flex-col gap-6">
  <Field>{/* ... */}</Field>
  <Field>{/* ... */}</Field>
</FieldGroup>
```

### Field

The core wrapper for a single field. Provides orientation control, invalid state styling, and spacing.

| Prop           | Type                                         | Default      |
| -------------- | -------------------------------------------- | ------------ |
| `orientation`  | `"vertical" \| "horizontal" \| "responsive"` | `"vertical"` |
| `className`    | `string`                                     |              |
| `data-invalid` | `boolean`                                    |              |

```tsx
<Field orientation="horizontal">
  <FieldLabel htmlFor="remember">Remember me</FieldLabel>
  <Switch id="remember" />
</Field>
```

### FieldContent

Flex column that groups control and descriptions when the label sits beside the control. Not required if you have no description.

| Prop        | Type     | Default |
| ----------- | -------- | ------- |
| `className` | `string` |         |

```tsx
<Field>
  <Checkbox id="notifications" />
  <FieldContent>
    <FieldLabel htmlFor="notifications">Notifications</FieldLabel>
    <FieldDescription>Email, SMS, and push options.</FieldDescription>
  </FieldContent>
</Field>
```

### FieldLabel

Label styled for both direct inputs and nested `Field` children.

| Prop        | Type     | Default |
| ----------- | -------- | ------- |
| `className` | `string` |         |

```tsx
<FieldLabel htmlFor="email">Email</FieldLabel>
```

### FieldTitle

Renders a title with label styling inside `FieldContent`.

| Prop        | Type     | Default |
| ----------- | -------- | ------- |
| `className` | `string` |         |

```tsx
<FieldContent>
  <FieldTitle>Enable Touch ID</FieldTitle>
  <FieldDescription>Unlock your device faster.</FieldDescription>
</FieldContent>
```

### FieldDescription

Helper text slot that automatically balances long lines in horizontal layouts.

| Prop        | Type     | Default |
| ----------- | -------- | ------- |
| `className` | `string` |         |

```tsx
<FieldDescription>We never share your email with anyone.</FieldDescription>
```

### FieldSeparator

Visual divider to separate sections inside a `FieldGroup`. Accepts optional inline content.

| Prop        | Type     | Default |
| ----------- | -------- | ------- |
| `className` | `string` |         |

```tsx
<FieldSeparator>Or continue with</FieldSeparator>
```

### FieldError

Accessible error container that accepts children or an `errors` array (e.g., from `react-hook-form`).

| Prop        | Type                                       | Default |
| ----------- | ------------------------------------------ | ------- |
| `errors`    | `Array<{ message?: string } \| undefined>` |         |
| `className` | `string`                                   |         |

```tsx
<FieldError errors={errors.username} />
```

When the `errors` array contains multiple messages, the component renders a list automatically.

`FieldError` also accepts issues produced by any validator that implements [Standard Schema](https://standardschema.dev/), including Zod, Valibot, and ArkType. Pass the `issues` array from the schema result directly to render a unified error list across libraries.

## Props

<div className="flex flex-row gap-x-3">
  <ExternalLink href="https://ui.shadcn.com/docs/components/field" text="Docs" />
</div>

## Credits

- We take our inspiration from [Shadcn UI](https://ui.shadcn.com/docs/components/field) for the `field` component and style.
