Field

Owns the label, description and error for one form control.

import { Field } from "@usefragments/ui";Source

Preview

<Field name="email">
  <Field.Label>Email address</Field.Label>
  <Input type="email" placeholder="jane@example.com" />
  <Field.Description>We will never share your email.</Field.Description>
</Field>

Usage

Use when

  • Any labelled Input, Textarea, Select, Combobox or NumberField
  • One error message per failure reason, not one catch-all
  • A custom control needs a real label and description
  • Server errors must land on the field that caused them

Avoid when

  • Naming a group of controls (use Fieldset)
  • A control with no visible label, such as a toolbar filter (give the control an aria-label)

Implementation notes

  • Every Field gets a Field.Label
  • Input, Textarea, Select, Combobox and NumberField join the field as direct children
  • Wrap a custom control in Field.Control so it joins the field context
  • Give each Field.Error a match so the message fits the failure; with no children it shows the browser's message
  • Nest inside Form to route server errors by field name

Installation

pnpm add @usefragments/ui

Import styles once from @usefragments/ui/styles. See the installation guide for framework and theme setup.

Anatomy

Import Field once, then compose its parts with dot notation.

  • Field.Label
  • Field.Control
  • Field.Description
  • Field.Error
  • Field.Validity
  • Field.Required

Label, control and description wired together.

<Field name="email">
  <Field.Label>Email address</Field.Label>
  <Input type="email" placeholder="jane@example.com" />
  <Field.Description>We will never share your email.</Field.Description>
</Field>

Examples

Two-column layout

Grid places two short fields side by side and one full-width.

<Grid columns={2} gap="md">
  <Field name="firstName">
    <Field.Label>First Name</Field.Label>
    <Input placeholder="Jane" />
  </Field>
  <Field name="lastName">

Invalid

invalid marks the field failed and reveals Field.Error.

<Field name="username" invalid>
  <Field.Label>Username</Field.Label>
  <Input defaultValue="ada lovelace" />
  <Field.Error match>Usernames cannot contain spaces</Field.Error>
</Field>

Select in a Field

The trigger takes the label; the error lands under it.

<Field name="team" invalid>
  <Field.Label>Team</Field.Label>
  <Select placeholder="Choose a team">
    <Select.Trigger />
    <Select.Content>
      <Select.Item value="design">Design</Select.Item>

Custom validation

validate runs on change and feeds Field.Error.

<Field
  name="age"
  validate={(value) => {
    const num = Number(value);
    if (isNaN(num) || num < 18) return 'Must be 18 or older';
    return null;

API reference

Component props
Prop
Type
Default
Description
childrenRequiredReact.ReactNodeNot setField content (Label, Control, Description, Error)
Control.childrenRequiredReact.ReactElement<unknown, string | React.JSXElementConstructor<any>>Not set—
Control.classNamestring | undefinedNot set—
Description.childrenRequiredReact.ReactNodeNot set—
Description.classNamestring | undefinedNot set—
disabledboolean | undefinedNot setDisables the field: dimmed once, and its control cannot be used
Error.childrenReact.ReactNodeNot setWhat went wrong and how to fix it. Omit to show the browser's validation message.
Error.classNamestring | undefinedNot set—
Error.matchboolean | "valueMissing" | "typeMismatch" | "tooShort" | "tooLong" | "patternMismatch" | "customError" | undefinedNot set—
invalidboolean | undefinedNot setMarks the field invalid: the control takes the danger edge and Field.Error shows
Label.childrenRequiredReact.ReactNodeNot set—
Label.classNamestring | undefinedNot set—
namestring | undefinedNot setField name, used for error distribution from Form
Required.childrenReact.ReactNodeNot set—
validate((value: unknown) => string | string[] | null | Promise<string | string[] | null>) | undefinedNot setCustom validation function returning error string(s) or null
validationDebounceTimenumber | undefinedNot setDebounce time in ms for onChange validation
validationMode"onBlur" | "onChange" | "onSubmit" | undefinedonBluronChangeonSubmitNot setWhen to trigger validation
Validity.childrenRequired(state: FieldValidityState) => React.ReactNodeNot set—

Accessibility

  • Label links to the control
  • Description links via aria-describedby
  • Field.Error is an alert with an icon, so the failure never relies on colour alone
  • data-disabled and data-invalid are available for styling
  • InputchildInput, Textarea, Select, Combobox and NumberField take their label from Field
  • FormparentWrap in Form for server-side error distribution
  • FieldsetsiblingUse Fieldset to group related fields

Next steps