# Fieldset

URL: https://ark-ui.com/docs/components/fieldset
Source: https://raw.githubusercontent.com/chakra-ui/ark/refs/heads/main/website/src/content/pages/components/fieldset.mdx

A set of form controls optionally grouped under a common name.

---

## Anatomy

<Anatomy id="fieldset" />

```tsx
<Fieldset.Root>
  <Fieldset.Legend />
  <Fieldset.HelperText />
  <Fieldset.ErrorText />
</Fieldset.Root>
```

## Examples

The `Fieldset` component provides contexts such as `invalid` and `disabled` for form elements. While most Ark UI
components natively support these contexts, you can also use the `Field` component with standard HTML form elements.

### Basic

**Example: basic**

```ripple
import { Field } from 'ark-ripple/field';
import { Fieldset } from 'ark-ripple/fieldset';
import field from 'styles/field.module.css';
import styles from 'styles/fieldset.module.css';

export component Basic() {
  <Fieldset.Root class={styles.Root}>
    <Fieldset.Legend class={styles.Legend}>{'Contact Details'}</Fieldset.Legend>

    <Field.Root class={field.Root}>
      <Field.Label class={field.Label}>{'Name'}</Field.Label>
      <Field.Input class={field.Input} placeholder="John Doe" />
    </Field.Root>

    <Field.Root class={field.Root}>
      <Field.Label class={field.Label}>{'Email'}</Field.Label>
      <Field.Input class={field.Input} type="email" placeholder="john@example.com" />
    </Field.Root>
  </Fieldset.Root>
}

```

### Field

This example demonstrates how to use the `Field` component with a standard input field within a `Fieldset`.

**Example: with-field**

```ripple
import { Field } from 'ark-ripple/field';
import { Fieldset } from 'ark-ripple/fieldset';
import field from 'styles/field.module.css';
import styles from 'styles/fieldset.module.css';

export component WithField() {
  <Fieldset.Root class={styles.Root}>
    <Fieldset.Legend class={styles.Legend}>{'Personal Information'}</Fieldset.Legend>

    <Field.Root class={field.Root}>
      <Field.Label class={field.Label}>{'First Name'}</Field.Label>
      <Field.Input class={field.Input} placeholder="Enter your first name" />
      <Field.HelperText class={field.HelperText}>{'As it appears on your ID'}</Field.HelperText>
    </Field.Root>

    <Field.Root class={field.Root}>
      <Field.Label class={field.Label}>{'Last Name'}</Field.Label>
      <Field.Input class={field.Input} placeholder="Enter your last name" />
    </Field.Root>
  </Fieldset.Root>
}

```

### Checkbox

This example shows how to use the `Fieldset` component with other Ark UI form elements like `Checkbox`.

**Example: with-checkbox**

```ripple
import { Checkbox } from 'ark-ripple/checkbox';
import { Fieldset } from 'ark-ripple/fieldset';
import { Check } from 'lucide-ripple';
import checkbox from 'styles/checkbox.module.css';
import styles from 'styles/fieldset.module.css';

export component WithCheckbox() {
  <Fieldset.Root class={styles.Root}>
    <Fieldset.Legend class={styles.Legend}>{'Email Preferences'}</Fieldset.Legend>

    <Checkbox.Root class={checkbox.Root} defaultChecked>
      <Checkbox.Control class={checkbox.Control}>
        <Checkbox.Indicator class={checkbox.Indicator}>
          <Check />
        </Checkbox.Indicator>
      </Checkbox.Control>
      <Checkbox.Label class={checkbox.Label}>{'Product updates'}</Checkbox.Label>
      <Checkbox.HiddenInput />
    </Checkbox.Root>

    <Checkbox.Root class={checkbox.Root}>
      <Checkbox.Control class={checkbox.Control}>
        <Checkbox.Indicator class={checkbox.Indicator}>
          <Check />
        </Checkbox.Indicator>
      </Checkbox.Control>
      <Checkbox.Label class={checkbox.Label}>{'Marketing emails'}</Checkbox.Label>
      <Checkbox.HiddenInput />
    </Checkbox.Root>
  </Fieldset.Root>
}

```

### Root Provider

An alternative way to control the fieldset is to use the `RootProvider` component and the `useFieldset` hook. This way
you can access the state and methods from outside the component.

**Example: root-provider**

```ripple
import { Field } from 'ark-ripple/field';
import { Fieldset, useFieldset } from 'ark-ripple/fieldset';
import field from 'styles/field.module.css';
import styles from 'styles/fieldset.module.css';

export component RootProvider() {
  const fieldset = useFieldset();

  <Fieldset.RootProvider class={styles.Root} value={fieldset}>
    <Fieldset.Legend class={styles.Legend}>{'Contact Details'}</Fieldset.Legend>

    <Field.Root class={field.Root}>
      <Field.Label class={field.Label}>{'Name'}</Field.Label>
      <Field.Input class={field.Input} placeholder="John Doe" />
    </Field.Root>

    <Field.Root class={field.Root}>
      <Field.Label class={field.Label}>{'Email'}</Field.Label>
      <Field.Input class={field.Input} type="email" placeholder="john@example.com" />
    </Field.Root>
  </Fieldset.RootProvider>
}

```

### Input with Select

This example shows how to use the `Fieldset` component with `Field.Input` and `Select` to create a interactive phone
input component.

**Example: phone-input**

```ripple
import { Fieldset } from 'ark-ripple/fieldset';
import { Field } from 'ark-ripple/field';
import { track } from 'ripple';
import { Portal } from 'ark-ripple/portal';
import { Select, createListCollection } from 'ark-ripple/select';
import { ChevronsUpDown } from 'lucide-ripple';
import styles from 'styles/fieldset.module.css';
import field from 'styles/field.module.css';
import select from 'styles/select.module.css';

const extensions = createListCollection(
  {
    items: [
      { label: '+1', value: '+1' },
      { label: '+44', value: '+44' },
      { label: '+49', value: '+49' },
      { label: '+41', value: '+41' },
    ],
  },
);

export component PhoneInput() {
  let inputRef = track<HTMLInputElement | null>(null);

  const focusInput = () => {
    setTimeout(() => {
      @inputRef?.focus();
    });
  };

  <Fieldset.Root class={styles.Root}>
    <Fieldset.Legend class={styles.Legend} onClick={focusInput}>{'Mobile Number'}</Fieldset.Legend>

    <div style={{ display: 'flex', alignItems: 'flex-start', gap: '0.5rem' }}>
      <Field.Root>
        <Select.Root
          class={select.Root}
          collection={extensions}
          defaultValue={['+1']}
          onValueChange={focusInput}
        >
          <Select.Control class={select.Control}>
            <Select.Trigger class={select.Trigger}>
              <Select.ValueText placeholder="Select" />
              <ChevronsUpDown />
            </Select.Trigger>
          </Select.Control>
          <Portal>
            <Select.Positioner>
              <Select.Content class={select.Content}>
                for (const item of extensions.items; key item.value) {
                  <Select.Item class={select.Item} {item}>
                    <Select.ItemText class={select.ItemText}>{item.label}</Select.ItemText>
                  </Select.Item>
                }
              </Select.Content>
            </Select.Positioner>
          </Portal>
          <Select.HiddenSelect />
        </Select.Root>
      </Field.Root>

      <Field.Root class={field.Root}>
        <Field.Input
          class={field.Input}
          {ref (el: HTMLInputElement) => {
            @inputRef = el;
            return () => {
              @inputRef = null;
            };
          }}
        />
      </Field.Root>
    </div>
  </Fieldset.Root>
}

```

## API Reference

**Component API Reference**

**Root Props:**

| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. |
| `invalid` | `boolean` | No | Indicates whether the fieldset is invalid. |


**ErrorText Props:**

| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. |


**HelperText Props:**

| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. |


**Legend Props:**

| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. |


**RootProvider Props:**

| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `value` | `{ refs: { rootRef: RefObject<HTMLFieldSetElement | null>; }; ids: { legend: string; errorText: string; helperText: string; }; disabled: boolean; invalid: boolean; getRootProps: () => Omit<...>; getLegendProps: () => Omit<...>; getHelperTextProps: () => Omit<...>; getErrorTextProps: () => Omit<...>; }` | Yes |  |
| `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. |
