Fieldset
A shadcn-style fieldset component built with Ark UI primitives.
import {
Field,
FieldDescription,
FieldInput,
FieldLabel,
} from "@/components/ui/field";
import { Fieldset, FieldsetLegend } from "@/components/ui/fieldset";
const FieldsetBillingDemo = () => (
<Fieldset className="max-w-md">
<FieldsetLegend>Billing details</FieldsetLegend>
<Field>
<FieldLabel>Company</FieldLabel>
<FieldInput placeholder="Enter company name" type="text" />
<FieldDescription>
The name that will appear on invoices.
</FieldDescription>
</Field>
<Field>
<FieldLabel>Tax ID</FieldLabel>
<FieldInput placeholder="Enter tax identification number" type="text" />
<FieldDescription>
Your business tax identification number.
</FieldDescription>
</Field>
</Fieldset>
);
export default FieldsetBillingDemo;
Installation
npx shadcn@latest add @ark-cn/fieldsetInstall the dependency required by this primitive:
npm install @ark-ui/reactCopy the component source into your app:
TSXcomponents/ui/fieldset.tsx
"use client";
import {
FieldsetContext,
Fieldset as FieldsetPrimitive,
FieldsetRootProvider,
useFieldset,
useFieldsetContext,
} from "@ark-ui/react/fieldset";
import { cn } from "@/lib/utils";
export const Fieldset = ({
className,
...props
}: FieldsetPrimitive.RootProps) => (
<FieldsetPrimitive.Root
className={cn(
"flex w-full min-w-0 flex-col gap-3 border-0 p-0 text-foreground",
className,
)}
data-slot="fieldset"
{...props}
/>
);
export const FieldsetLegend = (props: FieldsetPrimitive.LegendProps) => {
const { className, ...rest } = props;
return (
<FieldsetPrimitive.Legend
data-slot="fieldset-legend"
className={cn(
"mb-1 p-0 font-semibold text-base text-foreground leading-normal",
"data-disabled:pointer-events-none data-disabled:opacity-50",
className,
)}
{...rest}
/>
);
};
export const FieldsetDescription = ({
className,
...props
}: FieldsetPrimitive.HelperTextProps) => (
<FieldsetPrimitive.HelperText
data-slot="fieldset-description"
className={cn(
"text-muted-foreground text-xs",
"data-disabled:pointer-events-none data-disabled:opacity-50",
className,
)}
{...props}
/>
);
export const FieldsetError = ({
className,
...props
}: FieldsetPrimitive.ErrorTextProps) => (
<FieldsetPrimitive.ErrorText
data-slot="fieldset-error"
className={cn(
"text-destructive text-xs",
"data-disabled:pointer-events-none data-disabled:opacity-50",
className,
)}
{...props}
/>
);
export type {
FieldsetRootProviderProps,
UseFieldsetProps,
UseFieldsetReturn,
} from "@ark-ui/react/fieldset";
export {
FieldsetContext,
FieldsetRootProvider,
useFieldset,
useFieldsetContext,
};
Update import aliases to match your project setup.
Usage
import * as Fieldset from "@/components/ui/fieldset"Read exported parts in src/components/ui/fieldset.tsx and compose the primitive according to the Ark UI pattern for this component.
Examples
Billing
import {
Field,
FieldDescription,
FieldInput,
FieldLabel,
} from "@/components/ui/field";
import { Fieldset, FieldsetLegend } from "@/components/ui/fieldset";
const FieldsetBillingDemo = () => (
<Fieldset className="max-w-md">
<FieldsetLegend>Billing details</FieldsetLegend>
<Field>
<FieldLabel>Company</FieldLabel>
<FieldInput placeholder="Enter company name" type="text" />
<FieldDescription>
The name that will appear on invoices.
</FieldDescription>
</Field>
<Field>
<FieldLabel>Tax ID</FieldLabel>
<FieldInput placeholder="Enter tax identification number" type="text" />
<FieldDescription>
Your business tax identification number.
</FieldDescription>
</Field>
</Fieldset>
);
export default FieldsetBillingDemo;
Checkbox
import {
Checkbox,
CheckboxLabel,
CheckboxRoot,
} from "@/components/ui/checkbox";
import { Fieldset, FieldsetLegend } from "@/components/ui/fieldset";
const FieldsetCheckboxDemo = () => (
<Fieldset className="max-w-md">
<FieldsetLegend>Email preferences</FieldsetLegend>
<CheckboxRoot defaultChecked>
<Checkbox />
<CheckboxLabel>Product updates</CheckboxLabel>
</CheckboxRoot>
<CheckboxRoot>
<Checkbox />
<CheckboxLabel>Marketing emails</CheckboxLabel>
</CheckboxRoot>
</Fieldset>
);
export default FieldsetCheckboxDemo;
import {
Field,
FieldDescription,
FieldInput,
FieldLabel,
} from "@/components/ui/field";
import { Fieldset, FieldsetLegend } from "@/components/ui/fieldset";
const FieldsetBillingDemo = () => (
<Fieldset className="max-w-md">
<FieldsetLegend>Billing details</FieldsetLegend>
<Field>
<FieldLabel>Company</FieldLabel>
<FieldInput placeholder="Enter company name" type="text" />
<FieldDescription>
The name that will appear on invoices.
</FieldDescription>
</Field>
<Field>
<FieldLabel>Tax ID</FieldLabel>
<FieldInput placeholder="Enter tax identification number" type="text" />
<FieldDescription>
Your business tax identification number.
</FieldDescription>
</Field>
</Fieldset>
);
export default FieldsetBillingDemo;
Disabled
import { Field, FieldInput, FieldLabel } from "@/components/ui/field";
import { Fieldset, FieldsetLegend } from "@/components/ui/fieldset";
const FieldsetDisabledDemo = () => (
<Fieldset className="max-w-md" disabled>
<FieldsetLegend>Read-only profile</FieldsetLegend>
<Field disabled>
<FieldLabel>Name</FieldLabel>
<FieldInput defaultValue="Jane Doe" disabled />
</Field>
<Field disabled>
<FieldLabel>Email</FieldLabel>
<FieldInput defaultValue="jane@example.com" disabled type="email" />
</Field>
</Fieldset>
);
export default FieldsetDisabledDemo;
Invalid
import {
Field,
FieldError,
FieldInput,
FieldLabel,
} from "@/components/ui/field";
import {
Fieldset,
FieldsetError,
FieldsetLegend,
} from "@/components/ui/fieldset";
const FieldsetInvalidDemo = () => (
<Fieldset className="max-w-md" invalid>
<FieldsetLegend>Account information</FieldsetLegend>
<FieldsetError>Please fix the errors below to continue.</FieldsetError>
<Field invalid>
<FieldLabel>Username</FieldLabel>
<FieldInput defaultValue="jo" />
<FieldError>Username must be at least 3 characters</FieldError>
</Field>
<Field invalid>
<FieldLabel>Email</FieldLabel>
<FieldInput defaultValue="invalid-email" type="email" />
<FieldError>Please enter a valid email address</FieldError>
</Field>
</Fieldset>
);
export default FieldsetInvalidDemo;
Root Provider
import { Field, FieldInput, FieldLabel } from "@/components/ui/field";
import {
FieldsetLegend,
FieldsetRootProvider,
useFieldset,
} from "@/components/ui/fieldset";
const FieldsetRootProviderDemo = () => {
const fieldset = useFieldset({ id: "showcase-fieldset-provider" });
return (
<FieldsetRootProvider
className="flex w-full max-w-md min-w-0 flex-col gap-3 border-0 p-0 text-foreground"
value={fieldset}
>
<FieldsetLegend {...fieldset.getLegendProps()}>
Contact details
</FieldsetLegend>
<Field>
<FieldLabel>Name</FieldLabel>
<FieldInput placeholder="John Doe" />
</Field>
<Field>
<FieldLabel>Email</FieldLabel>
<FieldInput placeholder="john@example.com" type="email" />
</Field>
</FieldsetRootProvider>
);
};
export default FieldsetRootProviderDemo;
API reference
This component mirrors the upstream Ark UI primitive.
See the ARK UI documentation for the full API.