Navigation: [/sitemap.md](/sitemap.md)

---
type: doc
title: Field
description: Combine labels, controls, and help text to compose accessible form fields and grouped inputs.
---

```astro live props={{ name: 'field' }}
---
import { Checkbox } from "@/components/ui/checkbox"
import {
  Field,
  FieldDescription,
  FieldGroup,
  FieldLabel,
  FieldLegend,
  FieldSet,
} from "@/components/ui/field"
import { Input } from "@/components/ui/input"
---

<FieldSet>
  <FieldLegend>Profile</FieldLegend>
  <FieldDescription>Enter your profile information below.</FieldDescription>
  <FieldGroup>
    <Field>
      <FieldLabel for="name">Full name</FieldLabel>
      <Input type="text" id="name" placeholder="Evil Rabbit" />
      <FieldDescription>This appears on invoices and emails.</FieldDescription>
    </Field>
    <Field>
      <FieldLabel for="username">Username</FieldLabel>
      <Input type="text" id="username" placeholder="evilrabbit" />
    </Field>
    <Field orientation="horizontal">
      <Checkbox id="newsletter" />
      <FieldLabel for="newsletter">Subscribe to the newsletter</FieldLabel>
    </Field>
  </FieldGroup>
</FieldSet>
```

## Installation

```bash
npx shadcn@latest add @fulldev/field
```

## Usage

```ts
import {
  Field,
  FieldContent,
  FieldDescription,
  FieldGroup,
  FieldLabel,
  FieldLegend,
  FieldSeparator,
  FieldSet,
  FieldTitle,
} from "@/components/ui/field"
```

```astro
<FieldSet>
  <FieldLegend>Profile</FieldLegend>
  <FieldGroup>
    <Field>
      <FieldLabel for="name">Full name</FieldLabel>
      <Input id="name" placeholder="Evil Rabbit" />
      <FieldDescription>Optional helper text.</FieldDescription>
    </Field>
  </FieldGroup>
</FieldSet>
```

## Composition

Use the following composition for a single field with a label, control, helper text, and validation:

```text
Field
├── FieldLabel
├── Input / Textarea / Switch / Select
├── FieldDescription
└── FieldError
```

Use `FieldGroup` to group related fields. Add `FieldSeparator` between sections when needed.

```text
FieldGroup
├── Field
│   ├── FieldLabel
│   ├── Input / Textarea / Switch / Select
│   ├── FieldDescription
│   └── FieldError
├── FieldSeparator
└── Field
    ├── FieldLabel
    └── Input / Textarea / Switch / Select
```

Use `FieldSet` and `FieldLegend` for semantic grouping:

```text
FieldSet
├── FieldLegend
├── FieldDescription
└── FieldGroup
    ├── Field
    │   ├── FieldLabel
    │   ├── Input / Textarea / Switch / Select
    │   ├── FieldDescription
    │   └── FieldError
    └── Field
        ├── FieldLabel
        └── Input / Textarea / Switch / Select
```

## Anatomy

The `Field` family is designed for composing accessible forms. A typical field is structured as follows:

```astro
<Field>
  <FieldLabel for="input-id">Label</FieldLabel>
  <!-- Input, Select, Checkbox, etc. -->
  <FieldDescription>Optional helper text.</FieldDescription>
</Field>
```

- `Field` is the core wrapper for a single field.
- `FieldContent` is a flex column that groups label and description. Not required if you have no description.
- Wrap related fields with `FieldGroup`, and use `FieldSet` with `FieldLegend` for semantic grouping.

## Examples

```astro live
---
import { Field, FieldDescription, FieldLabel } from "@/components/ui/field"
import { Input } from "@/components/ui/input"
---

<div class="w-full max-w-sm">
  <Field>
    <FieldLabel for="email">Email</FieldLabel>
    <Input id="email" type="email" placeholder="email@example.com" />
    <FieldDescription>We'll never share your email.</FieldDescription>
  </Field>
</div>
```

```astro live
---
import { Field, FieldDescription, FieldLabel } from "@/components/ui/field"
import { Textarea } from "@/components/ui/textarea"
---

<div class="w-full max-w-sm">
  <Field>
    <FieldLabel for="bio">Bio</FieldLabel>
    <Textarea id="bio" placeholder="Tell us about yourself" />
    <FieldDescription>Write a short bio about yourself.</FieldDescription>
  </Field>
</div>
```

```astro live
---
import { Field, FieldDescription, FieldLabel } from "@/components/ui/field"
import { NativeSelect, NativeSelectOption } from "@/components/ui/native-select"
---

<div class="w-full max-w-sm">
  <Field>
    <FieldLabel for="country">Country</FieldLabel>
    <NativeSelect id="country">
      <NativeSelectOption value="">Select a country</NativeSelectOption>
      <NativeSelectOption value="us">United States</NativeSelectOption>
      <NativeSelectOption value="uk">United Kingdom</NativeSelectOption>
      <NativeSelectOption value="ca">Canada</NativeSelectOption>
    </NativeSelect>
    <FieldDescription>Select your country of residence.</FieldDescription>
  </Field>
</div>
```

```astro live
---
import {
  Field,
  FieldDescription,
  FieldGroup,
  FieldLabel,
  FieldLegend,
  FieldSet,
} from "@/components/ui/field"
import { Input } from "@/components/ui/input"
---

<div class="w-full max-w-sm">
  <FieldSet>
    <FieldLegend>Personal Information</FieldLegend>
    <FieldDescription>Enter your personal details below.</FieldDescription>
    <FieldGroup>
      <Field>
        <FieldLabel for="first-name">First name</FieldLabel>
        <Input id="first-name" placeholder="John" />
      </Field>
      <Field>
        <FieldLabel for="last-name">Last name</FieldLabel>
        <Input id="last-name" placeholder="Doe" />
      </Field>
    </FieldGroup>
  </FieldSet>
</div>
```

```astro live
---
import { Checkbox } from "@/components/ui/checkbox"
import {
  Field,
  FieldContent,
  FieldDescription,
  FieldLabel,
} from "@/components/ui/field"
---

<div class="w-full max-w-sm">
  <Field orientation="horizontal">
    <Checkbox id="terms" />
    <FieldContent>
      <FieldLabel for="terms">Accept terms and conditions</FieldLabel>
      <FieldDescription>
        You agree to our Terms of Service and Privacy Policy.
      </FieldDescription>
    </FieldContent>
  </Field>
</div>
```

```astro live
---
import {
  Field,
  FieldDescription,
  FieldLabel,
  FieldLegend,
  FieldSet,
} from "@/components/ui/field"
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"
---

<div class="w-full max-w-sm">
  <FieldSet>
    <FieldLegend>Notifications</FieldLegend>
    <FieldDescription>Choose how you want to be notified.</FieldDescription>
    <RadioGroup defaultValue="email" name="notifications">
      <Field orientation="horizontal">
        <RadioGroupItem value="email" id="email" />
        <FieldLabel for="email">Email</FieldLabel>
      </Field>
      <Field orientation="horizontal">
        <RadioGroupItem value="sms" id="sms" />
        <FieldLabel for="sms">SMS</FieldLabel>
      </Field>
      <Field orientation="horizontal">
        <RadioGroupItem value="push" id="push" />
        <FieldLabel for="push">Push notification</FieldLabel>
      </Field>
    </RadioGroup>
  </FieldSet>
</div>
```

### Field Group

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

```astro live
---
import {
  Field,
  FieldDescription,
  FieldGroup,
  FieldLabel,
  FieldSeparator,
} from "@/components/ui/field"
import { Input } from "@/components/ui/input"
---

<div class="w-full max-w-sm">
  <FieldGroup>
    <Field>
      <FieldLabel for="email-group">Email</FieldLabel>
      <Input id="email-group" type="email" placeholder="email@example.com" />
      <FieldDescription>Your primary email address.</FieldDescription>
    </Field>
    <FieldSeparator>Or</FieldSeparator>
    <Field>
      <FieldLabel for="phone">Phone</FieldLabel>
      <Input id="phone" type="tel" placeholder="+1 (555) 000-0000" />
      <FieldDescription>Your phone number for SMS updates.</FieldDescription>
    </Field>
  </FieldGroup>
</div>
```

## 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.

```astro live
---
import { Checkbox } from "@/components/ui/checkbox"
import {
  Field,
  FieldContent,
  FieldDescription,
  FieldGroup,
  FieldLabel,
} from "@/components/ui/field"
---

<div class="w-full max-w-2xl">
  <FieldGroup class="@container/field-group">
    <Field orientation="responsive">
      <Checkbox id="responsive-checkbox" />
      <FieldContent>
        <FieldLabel for="responsive-checkbox">
          Analytics and performance
        </FieldLabel>
        <FieldDescription>
          Help improve the app by sharing anonymous usage data.
        </FieldDescription>
      </FieldContent>
    </Field>
    <Field orientation="responsive">
      <Checkbox id="responsive-marketing" />
      <FieldContent>
        <FieldLabel for="responsive-marketing">Marketing emails</FieldLabel>
        <FieldDescription>
          Receive emails about new products and features.
        </FieldDescription>
      </FieldContent>
    </Field>
  </FieldGroup>
</div>
```

## Validation

Add `data-invalid="true"` to `Field` to switch the entire block into an error state, and add `aria-invalid="true"` on the input itself for assistive technologies.

```astro live
---
import { Field, FieldDescription, FieldLabel } from "@/components/ui/field"
import { Input } from "@/components/ui/input"
---

<div class="w-full max-w-sm">
  <Field data-invalid="true">
    <FieldLabel for="error-email">Email</FieldLabel>
    <Input id="error-email" type="email" aria-invalid="true" />
    <FieldDescription class="text-destructive">
      Enter a valid email address.
    </FieldDescription>
    <FieldDescription
      >This email will be used for account notifications.</FieldDescription
    >
  </Field>
</div>
```

## Accessibility

- `FieldSet` and `FieldLegend` keep related controls grouped for keyboard and assistive tech users.
- `Field` outputs `role="group"` so nested controls inherit labeling from `FieldLabel` and `FieldLegend` when combined.
- Apply `FieldSeparator` sparingly to ensure screen readers encounter clear section boundaries.

## API Reference

See the [GitHub source code](https://github.com/fulldotdev/ui/tree/main/src/components/ui/field) for more information on props.
