Forms

Fieldset

A titled group of related fields, such as an address, rendered as a <fieldset> named by its legend. disabled disables every native control and every Field inside it at once.

Billing address

Where your card statements go.

In Spoonjoy

Spoonjoy, a recipe app, is built with Ouro HX (how).

In its source: app/components/notifications-section.tsx · app/routes/recipes.$id.steps.$stepId.edit.tsx · app/routes/recipes.$id.steps.new.tsx

Install

Once per app, with Tailwind CSS v4 and an @/* path alias (Ouro HX is built on Base UI, so --base base; skip -t in an existing app):

npx shadcn@latest init --base base --preset nova --yes --no-monorepo
npx shadcn@latest add ourostack/ouro-ui/ouro-base#v1.2.13

Then the component. From v0.8.0 it installs only the helpers it imports and never touches your stylesheet (Installing):

npx shadcn@latest add ourostack/ouro-ui/fieldset#v1.2.13

Or, with the @ouro namespace set up:

npx shadcn@latest add @ouro/ouro-base @ouro/fieldset

Its tests, stories and Playwright spec are optional. They need Vitest 4.1.11 or later, and from v0.8.0 never change a version your app has (Testing):

npx shadcn@latest add ourostack/ouro-ui/fieldset#v1.2.13 ourostack/ouro-ui/fieldset-tests#v1.2.13
import { Fieldset } from "@/components/ouro/field/fieldset";

Paths use shadcn's default @/ alias; the CLI rewrites them to yours.

Example

<Fieldset legend="Shipping address" description="Where we send your order.">
  <Field label="Street" name="street"><FieldControl autoComplete="street-address" /></Field>
  <Field label="City" name="city"><FieldControl autoComplete="address-level2" /></Field>
</Fieldset>

Usage

A group of checkboxes or radios that make one choice uses their group component, which takes the same legend.

Use instead when

  • Use Field instead for a single control.

Props

Type: FieldsetProps.

children (required)
Type: ReactNode
The fields and controls in the group.
className
Type: string
Layout only: margins, width, grid placement (mt-6). Appearance classes warn in development.
description
Type: ReactNode
Supporting text under the legend, read after it through aria-describedby.
disabled
Type: boolean
Disables every native control and every Field inside it, and fades the legend.
hideLegend
Type: boolean
Hides the legend visually; screen readers still read it as the group's name.
legend (required)
Type: string
What the group is, shown above it and read as the group's name. Required: a group of controls needs a name. To hide it visually, keep it and add hideLegend.

Don't use

These are not props. Passing one fails the type check with the fix in the error, and in development a console message names the fix.

  • label: Not a prop. Groups take legend: <Fieldset legend="Shipping address">.

className is for layout only

Pass margins, width and grid placement (mt-4, w-full, col-span-2). Your classes always win over Ouro UI's: Fieldset merges className last with cn (tailwind-merge), so a class that conflicts with its own replaces it.layout-classes

Appearance comes from props, not classes. In development, a class that sets appearance logs one warning per component instance, naming the prop to use instead. A class sets appearance when, after its variants (hover:, sm:) and any ! are removed, it starts with bg-, text-, border-, rounded-, shadow-, font-, ring-, from-, via-, to-, fill- or stroke-, or is border, rounded, shadow or ring, or has a dark: variant. Text wrapping, overflow and table layout classes (text-wrap, text-ellipsis, border-collapse) are layout and do not warn.

Alignment classes (text-center) warn too: set alignment on a parent element.

Claim sources