# Field

> The label, help text and error around a form control, wired to it for assistive technology.

Source: https://raft-design.botiverse.build/components/field. Generated from the current release; where it differs from what you remember, this page is right.

A field puts a label above a form control and help text below it, and replaces the help text with an error when the value is invalid. Every input, textarea and select in a form sits in a field.

```tsx
import { Field, FieldDescription, FieldLabel, Input } from "@botiverse/raft-ui";

export function FieldPreviewContent() {
  return (
    <Field className="w-80">
      <FieldLabel htmlFor="field-preview-email" required>
        Email
      </FieldLabel>
      <Input id="field-preview-email" type="email" placeholder="you@example.com" />
      <FieldDescription>Use your work email.</FieldDescription>
    </Field>
  );
}
```

## When to use

| Situation                                                   | Use                                                                                      |
| ----------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| A labeled control in a form: an input, a textarea, a select | Field                                                                                    |
| A checkbox, radio or switch with its label beside it        | Field with `FieldItem`                                                                   |
| A setting row with a switch                                 | A settings row ([ListRow](https://raft-design.botiverse.build/components/list-row.md)) with a [Switch](https://raft-design.botiverse.build/components/switch.md) |
| A section of a large form, with a heading and a description | [FormSection](https://raft-design.botiverse.build/components/form-section.md)                                           |

## Anatomy

- `Field`: the column that holds the parts. Required.
- `FieldLabel`: the label, above the control. Required unless the control has its own accessible name.
- The control: [Input](https://raft-design.botiverse.build/components/input.md), [InputGroup](https://raft-design.botiverse.build/components/input-group.md), [Textarea](https://raft-design.botiverse.build/components/textarea.md), [Select](https://raft-design.botiverse.build/components/select.md) or `FieldControl` for another native control.
- `FieldDescription`: help text below the control. Optional.
- `FieldError`: the error, in place of the help text. Shown only while the field is invalid.
- `FieldItem`: a row that puts a checkbox, radio or switch beside its label and description, 8px apart. It centres the control on the label's first line by moving it, so the row keeps its height: a switch overhangs the label's line rather than making the row taller. It works from its own line height, so **give it the same `size` as the label**: `<FieldItem size="sm">` with `<FieldLabel size="sm">`. A mismatch leaves the control 1px off ([Alignment](https://raft-design.botiverse.build/foundations/alignment.md#a-control-and-its-label)).
- `FieldValidity`: read access to the field's validity state, for custom messages.

## Variants

| Variant                | Use for                                                          |
| ---------------------- | ---------------------------------------------------------------- |
| `FieldLabel` default   | Form fields                                                      |
| `FieldLabel size="sm"` | Dense layouts where the default label is too large for the space |

```tsx
import { Field, FieldDescription, FieldLabel, Input } from "@botiverse/raft-ui";

export function FieldCompactLabelContent() {
  return (
    <Field className="w-80">
      <FieldLabel htmlFor="compact-label-display-name" size="sm">
        Display name
      </FieldLabel>
      <Input id="compact-label-display-name" aria-describedby="compact-label-description" />
      <FieldDescription id="compact-label-description">
        Shown to other workspace members.
      </FieldDescription>
    </Field>
  );
}
```

## States

```tsx
import { Input } from "@botiverse/raft-ui";
import { Field, FieldError, FieldLabel } from "@botiverse/raft-ui";

export function FieldContent() {
  return (
    <Field className="w-72" invalid>
      <FieldLabel htmlFor="field-error-email">Email</FieldLabel>
      <Input
        id="field-error-email"
        type="email"
        data-invalid
        defaultValue="oops"
        placeholder="you@example.com"
      />
      <FieldError match>Email is required.</FieldError>
    </Field>
  );
}
```

- **Invalid:** set `invalid` on `Field` and `data-invalid` on the control. The control's border turns `danger-strong`, and `FieldError` takes the place of `FieldDescription`, in `danger-strong`. When to check and how the message reads are in [Forms](https://raft-design.botiverse.build/patterns/forms.md#validation).
- **Disabled:** `disabled` on `Field` turns the label, help text and error `foreground-disabled`.

## Content

Where the label and help text go is in [Forms](https://raft-design.botiverse.build/patterns/forms.md#fields).

- Keep the label visible at all times. Don't use a floating label or a placeholder in its place.
- Write the label in sentence case: Agent name.
- Mark an optional field with `optional`, which adds "(optional)". Don't mark required fields: marking the optional ones is enough.
- Make the help text one line about what the value is for: Shown in chat and on tasks.
- Make the error say how to fix the value, with a correct example: Use lowercase and dashes: launch-week ([Writing](https://raft-design.botiverse.build/content/writing.md#do-and-dont)).
- A label, help text or error of any length wraps, and breaks inside a word that is wider than the line, so it never pushes the field, a dialog or the screen wider. `FieldItem` lets its label column shrink for the same reason ([Forms](https://raft-design.botiverse.build/patterns/forms.md#long-values-in-fields)).

## Accessibility

Field wraps Base UI Field. It connects the label, the description and the error to a Base UI control (Input, Select, Checkbox, Switch, RadioGroup) and passes the field's invalid and disabled state to it.

- Give `FieldLabel` an `htmlFor` that matches the control's `id` when the control is not a Base UI one, such as [Textarea](https://raft-design.botiverse.build/components/textarea.md), and point `aria-describedby` at the description.
- `FieldError` has `role="alert"`, so the error is announced when it appears.

## API

### Field

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `actionsRef` | `RefObject<FieldRootActions \| null>` |  | A ref to imperative actions. - `validate`: Validates the field when called. |
| `dirty` | `boolean` |  | Whether the field's value has been changed from its initial value. Useful when the field state is controlled by an external library. |
| `disabled` | `boolean` | `false` | Whether the component should ignore user interaction. Takes precedence over the `disabled` prop on the `<Field.Control>` component. |
| `invalid` | `boolean` |  | Whether the field is invalid. Useful when the field state is controlled by an external library. |
| `name` | `string` |  | Identifies the field when a form is submitted. Takes precedence over the `name` prop on the `<Field.Control>` component. |
| `render` | `ReactElement \| ((props, state) => ReactElement)` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component. |
| `touched` | `boolean` |  | Whether the field has been touched. Useful when the field state is controlled by an external library. |
| `validate` | `(value: unknown, formValues: Form.Values) => string \| string[] \| null \| void \| Promise<string \| string[] \| null \| void>` |  | A function for custom validation. Return a string or an array of strings with the error message(s) if the value is invalid. Returning nothing, `null`, an empty string, or an empty array means the value is valid. Asynchronous functions are supported, but they do not prevent form submission when using `validationMode="onSubmit"`. |
| `validationDebounceTime` | `number` | `0` | How long to wait between `validate` callbacks if `validationMode="onChange"` is used. Specified in milliseconds. |
| `validationMode` | `FormValidationMode` | `'onSubmit'` | Determines when the field should be validated. This takes precedence over the `validationMode` prop on `<Form>`. |

Also takes the attributes of its element.

### FieldControl

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `defaultValue` | `string \| number \| readonly string[]` |  |  |
| `onValueChange` | `(value: string, eventDetails: BaseField.Control.ChangeEventDetails) => void` |  | Callback fired when the `value` changes. Use when controlled. |
| `render` | `ReactElement \| ((props, state) => ReactElement)` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component. |

Also takes the attributes of its element.

### FieldDescription

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `render` | `ReactElement \| ((props, state) => ReactElement)` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component. |

Also takes the attributes of its element.

### FieldError

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `match` | `boolean \| keyof ValidityState` |  | Determines whether to show the error message according to the field's [ValidityState](https://developer.mozilla.org/en-US/docs/Web/API/ValidityState). Specifying `true` will always show the error message, and lets external libraries control the visibility. |
| `render` | `ReactElement \| ((props, state) => ReactElement)` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component. |

Also takes the attributes of its element.

### FieldItem

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `size` | `"sm" \| "md"` | `"md"` |  |
| `disabled` | `boolean` | `false` | Whether the wrapped control should ignore user interaction. The `disabled` prop on `<Field.Root>` takes precedence over this. |
| `render` | `ReactElement \| ((props, state) => ReactElement)` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component. |

Also takes the attributes of its element.

### FieldLabel

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `optional` | `boolean` |  |  |
| `required` | `boolean` |  |  |
| `size` | `"sm" \| "md"` | `"md"` |  |
| `nativeLabel` | `boolean` | `true` | Whether the component renders a native `<label>` element when replacing it via the `render` prop. Set to `false` if the rendered element is not a label (for example, `<div>`). |
| `render` | `ReactElement \| ((props, state) => ReactElement)` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component. |

Also takes the attributes of its element.

### FieldValidity

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `children` (required) | `(state: FieldValidityState) => React.ReactNode` |  | A function that accepts the field validity state as an argument. |

## Changes

- 0.8.0 (Breaking Changes): `FieldLabel` no longer carries `leading-none`. tailwind-merge already dropped it beside the type class, so most labels don't change, but a label whose class list kept it is now a full line high.
- 0.8.0 (Added): `FieldItem` takes `size` (`sm`, `md`), to match the size of its label.
