Field
Compose labels, inputs, helper text, and validation into a consistent field.
Preview
Field provides the structure around a control. The input remains responsible for its value, native behavior, and validation attributes.
Used for account notifications.
These examples use Migoy Input, available as a separate registry item. This page covers text inputs and form structure; examples for other controls will follow when those components are ready.
Installation
pnpm dlx shadcn@latest add http://127.0.0.1:3017/r/field.jsonInstalls Field, its structural Separator helper, and the Migoy Label dependency. It preserves your theme and global CSS. Input and Button are not bundled; use the controls already in your project. The local registry endpoint is a development snapshot.
Composition
import {
Field, FieldDescription, FieldError, FieldGroup,
FieldLabel, FieldLegend, FieldSet,
} from '@/components/ui/field';| Part | Purpose |
|---|---|
Field | Groups one control with its label and supporting text |
FieldLabel | Native label, composed from Migoy Label |
FieldDescription | Helper text, linked with aria-describedby |
FieldError | Error text or deduplicated errors messages; renders an alert |
FieldGroup | Stacks fields with a 16px gap |
FieldSet / FieldLegend | Native fieldset and legend for a related group |
FieldContent | Groups the label and description without added gap |
FieldSeparator | Optional structural separator between sections |
FieldTitle | Non-label title for compositions that need one |
Field does not generate IDs, connect descriptions automatically, or add a form library. Match htmlFor to the control's ID and explicitly connect helper and error text.
Field
One control with its label, optional description, and error. A standalone Field does not need a FieldSet or FieldGroup.
Used for account notifications.
FieldGroup
FieldGroup arranges multiple fields with a 16px gap. It provides layout, not a semantic group name.
Used for account notifications.
FieldSet
Use a native fieldset and legend when related fields need a shared name, such as Contact information. The legend and description have no added gap. When no description is present, leave 16px directly between the legend and fields. Otherwise, leave 16px between the description and fields; FieldGroup also spaces its fields 16px apart.
Invalid state
Mark the Field with data-invalid and the input with aria-invalid. The label stays neutral; the input border and error message use the destructive color. Link both helper text and the error with aria-describedby.
Used for account notifications.
<Field data-invalid>
<FieldLabel htmlFor="invalid-email">Email address</FieldLabel>
<Input id="invalid-email" aria-invalid aria-describedby="email-error" />
<FieldError id="email-error">Enter a valid email address.</FieldError>
</Field>FieldError accepts text children or errors={[{ message: 'Enter a valid email address.' }]}. Empty messages render nothing, and repeated messages are shown once.
Disabled state
Use data-disabled on Field to dim its label. Set disabled on the actual input to prevent interaction. A wrapper's visual state never disables the control by itself.
Used for account notifications.
Layout
Vertical is the default, with a 4px gap between a field's parts. Descriptions and errors use the caption role: 12px text, 16px line height, and regular weight. FieldContent stacks its label and description without an added gap. horizontal places the label region beside the control. responsive starts vertically and switches at the FieldGroup container's medium breakpoint.
Shown on your profile.
Form example
For a simple form, compose Field with native browser validation. Install Input and Button separately alongside Field. Replace the action with your product's submission endpoint:
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Field, FieldGroup, FieldLabel } from '@/components/ui/field';
export function ProfileForm() {
return (
<form action="/profile" method="post" className="flex flex-col gap-6">
<FieldGroup>
<Field>
<FieldLabel htmlFor="profile-name">Full name (required)</FieldLabel>
<Input id="profile-name" name="name" autoComplete="name" required />
</Field>
<Field>
<FieldLabel htmlFor="profile-email">Email address (required)</FieldLabel>
<Input id="profile-email" name="email" type="email" autoComplete="email" required />
</Field>
</FieldGroup>
<Button type="submit" className="self-start">Save profile</Button>
</form>
);
}Validate submitted values on the server as well. For custom errors, follow the invalid-state guidance above.
This local example uses native form submission events and browser input validity. Submit empty fields to see errors and focus move to the first invalid input. Fill both fields with valid values to clear the errors. No data leaves the page.
Accessibility
Use FieldSet and FieldLegend to name related controls. Keep labels visible, express required fields in words, and apply required to the control. Connect errors and descriptions explicitly and focus the first invalid control after submission. A placeholder does not replace a label.
Based on shadcn Field.