Fieldset
Groups related form controls under a shared legend, description, and helper text — built on Base UI's Fieldset primitive with four variants, five sizes, intent accents, and full RTL support.
Playground
Installation
pnpm add @tessinaui/uiUsage
import {
FieldsetRoot,
FieldsetLegend,
FieldsetHeader,
FieldsetDescription,
FieldsetBody,
FieldsetHelperText,
} from "@tessinaui/ui";<FieldsetRoot variant="outline">
<FieldsetHeader>
<FieldsetLegend required>Notification preferences</FieldsetLegend>
<FieldsetDescription>
Choose how you want to be notified about updates.
</FieldsetDescription>
</FieldsetHeader>
<FieldsetBody>
<Switch label="Email" defaultChecked />
<Switch label="SMS" />
<Switch label="Mobile push" />
</FieldsetBody>
<FieldsetHelperText>
You can change these later in account settings.
</FieldsetHelperText>
</FieldsetRoot>Showcase
When to use
Reach for Fieldset when you have a group of related form controls that share a single label, description, or validation message — notification preferences, permission lists, billing options, plan selection, etc. The browser-native <fieldset> it renders gives screen readers the right grouping, and the disabled prop cascades to every form control inside (a behaviour you can't replicate with a <div>).
For a single labeled input, use Field. For a row of toggleable choices, CheckboxGroup and RadioGroup compose naturally inside Fieldset.Body.
API Reference
FieldsetRoot props
| Prop | Type | Default | Description |
|---|---|---|---|
size | "xs" | "sm" | "md" | "lg" | "xl" | "md" | Scales legend, description, helper text, gap, and padding |
variant | "ghost" | "outline" | "filled" | "elevated" | "ghost" | Visual treatment — ghost is just structure, the others wrap everything in a card |
rounded | "none" | "sm" | "md" | "lg" | "full" | "md" | Card corner radius (only applies to non-ghost variants) |
intent | "none" | "primary" | "error" | "warning" | "success" | "info" | "none" | Drives the border accent on non-ghost variants and the default HelperText colour |
dir | "ltr" | "rtl" | "ltr" | Text direction |
orientation | "vertical" | "horizontal" | "vertical" | Default layout for FieldsetBody children |
disabled | boolean | false | Disables the fieldset and cascades to every form control inside (browser behaviour of <fieldset disabled>) |
invalid | boolean | false | Forces error styling regardless of intent |
render | Base UI render prop | — | Polymorphic — replace the rendered <fieldset> element |
FieldsetLegend props
| Prop | Type | Default | Description |
|---|---|---|---|
required | boolean | false | Shows a red * after the legend text |
optional | boolean | false | Shows a muted "(optional)" label after the legend text. Ignored when required is true |
leadingIcon | ReactNode | — | Icon rendered before the legend text |
Renders a Base UI Fieldset.Legend (a <div> automatically associated with the fieldset for accessibility).
FieldsetHeader props
A flex column wrapper grouping Legend + Description so they stack with consistent spacing above the body.
FieldsetDescription props
A muted paragraph below the legend. Use it to clarify the purpose of the group.
FieldsetBody props
| Prop | Type | Default | Description |
|---|---|---|---|
orientation | "vertical" | "horizontal" | inherited | Override the orientation set on the Root for this body only |
Lays out children with size-aware gap. Horizontal orientation wraps when content overflows.
FieldsetHelperText props
| Prop | Type | Default | Description |
|---|---|---|---|
intent | FieldsetIntent | inherited | Override the colour for this helper text only (defaults to the Root's intent, or error when invalid) |
leadingIcon | ReactNode | — | Status icon rendered before the helper text |
Notes
- Built on
@base-ui/react/fieldset— thedisabledprop cascades to descendant form controls via the native<fieldset disabled>behaviour. Fieldset.Headeris optional. You can place a bareFieldset.Legenddirectly in the root if you don't need a description.- Pair with
CheckboxGroup,RadioGroup, or anyFieldinstance for full form composition. InsideFieldset.Bodythey inherit the disabled + invalid context naturally. invalid={true}is convenience sugar — it setsintent="error"styling without changing the prop on the Root, which keeps the API ergonomic for form libraries that track validation separately.
Field
A text input field with a label, helper text, FieldDropdown prefix, Button suffix, leading/trailing icon buttons, a clearable button, and a character counter. Supports all intent states and full RTL layout.
Checkbox
A form control that lets users select one or more options. Supports checked, unchecked, and indeterminate states. Five sizes, five intents, label/description/error patterns, and a CheckboxGroup compound component with select-all support.