# Fieldset

> Semantic field grouping with legend. Native fieldset + legend styled to the terminal shell - the right container for any cluster of related form controls.

- Category: form
- Status: stable (since 0.3.0)
- A11y pattern: https://www.w3.org/WAI/ARIA/apg/patterns/
- Tokens: --font-mono, --foreground-primary, --foreground-secondary, --background-tertiary, --border-width-thin
- Playground: https://design.freecodecamp.org/playground#fieldset
- npm dependencies: `react@>=18 <20`
- Registry dependencies: [theme](https://design.freecodecamp.org/registry/theme.md)
- Files:
  - `Fieldset.tsx` → `src/ui/fieldset/Fieldset.tsx` (raw: https://design.freecodecamp.org/registry/fieldset/Fieldset.tsx)
  - `fieldset.css` → `src/ui/fieldset/fieldset.css` (raw: https://design.freecodecamp.org/registry/fieldset/fieldset.css)

## Install (copy source)

1. Ensure the theme is installed once per project - tokens.css + base.css imported globally, fonts available. See https://design.freecodecamp.org/registry/theme.md and https://design.freecodecamp.org/registry/starter.md.
2. Copy the files below into `src/ui/fieldset/` (adjust to your project layout) and import the CSS once from your global stylesheet, e.g. `@import './ui/fieldset/fieldset.css';`.
3. Colors, spacing and type come from tokens - tailor the component by editing the copied source; recolour by editing tokens.css, not the component CSS.

## Usage

Fieldset is the grouping container for related form controls. It renders
a native `<fieldset>` with an optional `<legend>`, carrying our border
and spacing tokens so the group reads as a single terminal block. Pair
it with FormGroup, FormControl, Checkbox, Radio, and friends.

## Accessibility

Uses the native `fieldset` + `legend` pair - screen readers announce the
legend as the group label for every control inside. Prefer this over an
ad-hoc `div` + heading pattern whenever a group of controls needs a
shared name. `disabled` cascades automatically; no extra ARIA needed.

## Example

```tsx
import { Fieldset } from './ui/fieldset/Fieldset';
import { RadioGroup, Radio } from './ui/radio/Radio';

<Fieldset legend="Notification cadence">
  <RadioGroup name="cadence" defaultValue="weekly">
    <Radio value="weekly" label="Weekly digest" />
    <Radio value="per-cert" label="Per-cert" />
    <Radio value="never" label="Never" />
  </RadioGroup>
</Fieldset>
```

## Props

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `legend` | `ReactNode` | no | - |  |
| `tone` | `enum` | no | `default` |  |

## Source: Fieldset.tsx

```tsx
import React, { forwardRef } from 'react';

export type FieldsetTone = 'default' | 'subtle';

export interface FieldsetProps extends React.FieldsetHTMLAttributes<HTMLFieldSetElement> {
  legend?: React.ReactNode;
  tone?: FieldsetTone;
}

export const Fieldset = forwardRef<HTMLFieldSetElement, FieldsetProps>(
  ({ legend, tone = 'default', className = '', children, ...rest }, ref) => {
    const classes = [
      'fieldset',
      tone !== 'default' && `fieldset--${tone}`,
      className
    ]
      .filter(Boolean)
      .join(' ');
    return (
      <fieldset ref={ref} className={classes} {...rest}>
        {legend !== undefined && (
          <legend className='fieldset__legend'>{legend}</legend>
        )}
        {children}
      </fieldset>
    );
  }
);
Fieldset.displayName = 'Fieldset';
```

## Source: fieldset.css

```css
.fieldset {
  border: var(--border-width-thin) solid var(--foreground-secondary);
  padding: 12px 16px 16px;
  margin: 0 0 16px;
  background: transparent;
}
.fieldset--subtle {
  border-color: var(--background-tertiary);
}
.fieldset__legend {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  font-weight: var(--fw-bold);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--foreground-primary);
  padding: 0 6px;
}
.fieldset[disabled] {
  opacity: 0.55;
}
```

## HTML / vanilla variant

```html
<fieldset class="fieldset">
  <legend class="fieldset__legend">Notification cadence</legend>
  <label class="radio"><input type="radio" name="cadence" /> Weekly digest</label>
</fieldset>
```

Interactive behaviours for plain HTML come from the vanilla runtime (data-uikit-* attributes): https://design.freecodecamp.org/registry/vanilla.md - or download https://design.freecodecamp.org/cdn/uikit.global.js once and self-host it (do not hotlink).

## For coding agents

This library is distributed as copyable source, not an npm package. Start at https://design.freecodecamp.org/registry/starter.md, discover components via https://design.freecodecamp.org/llms.txt, and copy files into the consuming project. Keep token names intact; recolour by editing the copied tokens.css.
