Development preview

Fieldset

Something has to hold all these form controls together.

Shipping details

Without this your odds of getting your order are low.

We currently only ship to North America.

If you have a tiger, we'd like to know about it.

import { Description, Field, FieldGroup, Fieldset, Label, Legend } from '@/components/fieldset'
import { Input } from '@/components/input'
import { Select } from '@/components/select'
import { Text } from '@/components/text'
import { Textarea } from '@/components/textarea'

function Example() {
  return (
    <form action="/orders" method="POST">
      {/* ... */}
      <Fieldset>
        <Legend>Shipping details</Legend>
        <Text>Without this your odds of getting your order are low.</Text>
        <FieldGroup>
          <Field>
            <Label>Street address</Label>
            <Input name="street_address" />
          </Field>
          <Field>
            <Label>Country</Label>
            <Select name="country">
              <option>Canada</option>
              <option>Mexico</option>
              <option>United States</option>
            </Select>
            <Description>We currently only ship to North America.</Description>
          </Field>
          <Field>
            <Label>Delivery notes</Label>
            <Textarea name="notes" />
            <Description>If you have a tiger, we'd like to know about it.</Description>
          </Field>
        </FieldGroup>
      </Fieldset>
      {/* ... */}
    </form>
  )
}

Component API

PropDefaultDescription
Fieldset extends the JSX <div> element
disabledfalseWhether or not to disable the entire fieldset.
layouttrueWhether or not to apply layout styles to children.
Legend extends the JSX <div> element
This component does not expose any component-specific props.
FieldGroup extends the JSX <div> element
This component does not expose any component-specific props.

Examples

Basic example

Use the Fieldset, Legend, Text, and FieldGroup components to group a subset of form controls together:

Shipping details

Without this your odds of getting your order are low.

We currently only ship to North America.

If you have a tiger, we'd like to know about it.

import { Description, Field, FieldGroup, Fieldset, Label, Legend } from '@/components/fieldset'
import { Input } from '@/components/input'
import { Select } from '@/components/select'
import { Text } from '@/components/text'
import { Textarea } from '@/components/textarea'

function Example() {
  return (
    <form action="/orders" method="POST">
      {/* ... */}
      <Fieldset>
        <Legend>Shipping details</Legend>
        <Text>Without this your odds of getting your order are low.</Text>
        <FieldGroup>
          <Field>
            <Label>Street address</Label>
            <Input name="street_address" />
          </Field>
          <Field>
            <Label>Country</Label>
            <Select name="country">
              <option>Canada</option>
              <option>Mexico</option>
              <option>United States</option>
            </Select>
            <Description>We currently only ship to North America.</Description>
          </Field>
          <Field>
            <Label>Delivery notes</Label>
            <Textarea name="notes" />
            <Description>If you have a tiger, we'd like to know about it.</Description>
          </Field>
        </FieldGroup>
      </Fieldset>
      {/* ... */}
    </form>
  )
}

Without legend

Use a Fieldset with aria-label to group a set of form controls together without a Legend:

We currently only ship to North America.

If you have a tiger, we'd like to know about it.

import { Description, Field, FieldGroup, Fieldset, Label } from '@/components/fieldset'
import { Input } from '@/components/input'
import { Select } from '@/components/select'
import { Textarea } from '@/components/textarea'

function Example() {
  return (
    <form action="/orders" method="POST">
      <Fieldset aria-label="Shipping details">
        <FieldGroup>
          <Field>
            <Label>Street address</Label>
            <Input name="street_address" />
          </Field>
          <Field>
            <Label>Country</Label>
            <Select name="country">
              <option>Canada</option>
              <option>Mexico</option>
              <option>United States</option>
            </Select>
            <Description>We currently only ship to North America.</Description>
          </Field>
          <Field>
            <Label>Delivery notes</Label>
            <Textarea name="notes" />
            <Description>If you have a tiger, we'd like to know about it.</Description>
          </Field>
        </FieldGroup>
      </Fieldset>
    </form>
  )
}

Without role

Use the FieldGroup component on its own to use it solely for layout, without adding role="group" and announcing it to assistive technology like a traditional fieldset:

We currently only ship to North America.

If you have a tiger, we'd like to know about it.

import { Description, Field, FieldGroup, Label } from '@/components/fieldset'
import { Input } from '@/components/input'
import { Select } from '@/components/select'
import { Textarea } from '@/components/textarea'

function Example() {
  return (
    <form action="/orders" method="POST">
      <FieldGroup>
        <Field>
          <Label>Street address</Label>
          <Input name="street_address" />
        </Field>
        <Field>
          <Label>Country</Label>
          <Select name="country">
            <option>Canada</option>
            <option>Mexico</option>
            <option>United States</option>
          </Select>
          <Description>We currently only ship to North America.</Description>
        </Field>
        <Field>
          <Label>Delivery notes</Label>
          <Textarea name="notes" />
          <Description>If you have a tiger, we'd like to know about it.</Description>
        </Field>
      </FieldGroup>
    </form>
  )
}

With grid layout

For more complex layouts like grids, use wrapper elements to create nested form control groups and style them yourself with utility classes:

Shipping details

Without this your odds of getting your order are low.

If you have a tiger, we'd like to know about it.

import { Description, Field, FieldGroup, Fieldset, Label, Legend } from '@/components/fieldset'
import { Input } from '@/components/input'
import { Select } from '@/components/select'
import { Text } from '@/components/text'
import { Textarea } from '@/components/textarea'

function Example() {
  return (
    <form action="/orders" method="POST">
      {/* ... */}
      <Fieldset>
        <Legend>Shipping details</Legend>
        <Text>Without this your odds of getting your order are low.</Text>
        <FieldGroup>
          <div className="grid grid-cols-1 gap-8 sm:grid-cols-2 sm:gap-4">
            <Field>
              <Label>First name</Label>
              <Input name="first_name" />
            </Field>
            <Field>
              <Label>Last name</Label>
              <Input name="last_name" />
            </Field>
          </div>
          <Field>
            <Label>Street address</Label>
            <Input name="street_address" />
          </Field>
          <div className="grid grid-cols-1 gap-8 sm:grid-cols-3 sm:gap-4">
            <Field className="sm:col-span-2">
              <Label>Country</Label>
              <Select name="country">
                <option>Canada</option>
                <option>Mexico</option>
                <option>United States</option>
              </Select>
            </Field>
            <Field>
              <Label>Postal code</Label>
              <Input name="postal_code" />
            </Field>
          </div>
          <Field>
            <Label>Delivery notes</Label>
            <Textarea name="notes" />
            <Description>If you have a tiger, we'd like to know about it.</Description>
          </Field>
        </FieldGroup>
      </Fieldset>
      {/* ... */}
    </form>
  )
}

With custom layout

Use a plain <div> instead of a FieldGroup along with the unstyled Field component from @headlessui/react to implement a fully custom layout:

Shipping details

Without this your odds of getting your order are low.

import { Fieldset, Label, Legend } from '@/components/fieldset'
import { Input } from '@/components/input'
import { Select } from '@/components/select'
import { Text } from '@/components/text'
import { Textarea } from '@/components/textarea'
import { Field as HeadlessField } from '@headlessui/react'

function Example() {
  return (
    <form action="/orders" method="POST">
      {/* ... */}
      <Fieldset>
        <Legend>Shipping details</Legend>
        <Text>Without this your odds of getting your order are low.</Text>
        <div data-slot="control" className="grid grid-cols-1 items-center gap-x-4 gap-y-6 sm:grid-cols-3">
          <HeadlessField className="grid grid-cols-[subgrid] sm:col-span-3">
            <Label>Full name</Label>
            <Input className="mt-3 sm:col-span-2 sm:mt-0" name="full_name" />
          </HeadlessField>
          <HeadlessField className="grid grid-cols-[subgrid] sm:col-span-3">
            <Label>Street address</Label>
            <Input className="mt-3 sm:col-span-2 sm:mt-0" name="street_address" />
          </HeadlessField>
          <HeadlessField className="grid grid-cols-[subgrid] sm:col-span-3">
            <Label>Country</Label>
            <Select className="mt-3 sm:col-span-2 sm:mt-0" name="country">
              <option>Canada</option>
              <option>Mexico</option>
              <option>United States</option>
            </Select>
          </HeadlessField>
          <HeadlessField className="grid grid-cols-[subgrid] sm:col-span-3">
            <Label>Delivery notes</Label>
            <Textarea className="mt-3 sm:col-span-2 sm:mt-0" name="notes" />
          </HeadlessField>
        </div>
      </Fieldset>
      {/* ... */}
    </form>
  )
}

Add data-slot="control" to a child of your Fieldset if you want it to receive the same layout styles as a FieldGroup.

Disabled state

Add the disabled prop to a Fieldset component to disable the entire fieldset:

Shipping details

Without this your odds of getting your order are low.

We currently only ship to North America.

If you have a tiger, we'd like to know about it.

import { Description, Field, FieldGroup, Fieldset, Label, Legend } from '@/components/fieldset'
import { Input } from '@/components/input'
import { Select } from '@/components/select'
import { Text } from '@/components/text'
import { Textarea } from '@/components/textarea'

function Example() {
  return (
    <form action="/orders" method="POST">
      {/* ... */}
      <Fieldset disabled>
        <Legend>Shipping details</Legend>
        <Text>Without this your odds of getting your order are low.</Text>
        <FieldGroup>
          <Field>
            <Label>Street address</Label>
            <Input name="street_address" />
          </Field>
          <Field>
            <Label>Country</Label>
            <Select name="country">
              <option>Canada</option>
              <option>Mexico</option>
              <option>United States</option>
            </Select>
            <Description>We currently only ship to North America.</Description>
          </Field>
          <Field>
            <Label>Delivery notes</Label>
            <Textarea name="notes" />
            <Description>If you have a tiger, we'd like to know about it.</Description>
          </Field>
        </FieldGroup>
      </Fieldset>
      {/* ... */}
    </form>
  )
}