# Field

Connects a label, a control, help text, and validation messages, so assistive technology announces them together. For a label, description, and single error, [Control and label](/components/control-and-label.md) is shorter.

```tsx
// demo.tsx
import {Field, Input} from '@earendil-works/elanor-react';

export default function FieldDemo() {
  return (
    <Field.Root name="email">
      <Field.Label>Email</Field.Label>
      <Input type="email" autoComplete="email" placeholder="name@example.com" />
      <Field.Description>Used for project notifications.</Field.Description>
    </Field.Root>
  );
}
```

## Usage

```tsx
import {Field, Input} from '@earendil-works/elanor-react';

<Field.Root name="email">
  <Field.Label>Email</Field.Label>
  <Input type="email" />
  <Field.Description />
  <Field.Error />
</Field.Root>;
```

## Validation

Field uses the control's native validation, such as `required` and `type="email"`. Give each `Field.Error` a `match` to show one message per failed rule. `validationMode="onBlur"` validates when focus leaves the control; the default validates on form submit.

```tsx
// validation.tsx
import {Field, Input} from '@earendil-works/elanor-react';

export default function FieldValidation() {
  return (
    <Field.Root name="email" validationMode="onBlur">
      <Field.Label>Email</Field.Label>
      <Input type="email" autoComplete="email" placeholder="name@example.com" required />
      <Field.Error match="valueMissing">Enter your email address.</Field.Error>
      <Field.Error match="typeMismatch">Enter a valid email address.</Field.Error>
    </Field.Root>
  );
}
```

## Other controls

Elanor's form controls, such as [Input](/components/input.md), connect to Field on their own. For a native input type without an Elanor control, such as `color`, use `Field.Control`. It renders an unstyled `input` that Field labels and validates.

```tsx
// control.tsx
import {Field} from '@earendil-works/elanor-react';

import styles from './control.module.css';

export default function FieldControl() {
  return (
    <Field.Root name="accent">
      <Field.Label>Accent color</Field.Label>
      <Field.Control type="color" defaultValue="#2b6584" className={styles.color} />
    </Field.Root>
  );
}
```

```css
/* control.module.css */
.color {
  inline-size: var(--semantic-dimension-size-large);
  block-size: var(--semantic-dimension-size-large);
  padding: 0;
  border: var(--semantic-dimension-border-width-default) solid
    var(--semantic-color-border-secondary);
  border-radius: var(--semantic-dimension-radius-small);
  background: none;
}
```

## API

### `Field.Root`

Accepts Base UI [`Field.Root`](https://base-ui.com/react/components/field.md) props.

### `Field.Label`

Accepts Base UI [`Field.Label`](https://base-ui.com/react/components/field.md) props.

### `Field.Description`

Accepts Base UI [`Field.Description`](https://base-ui.com/react/components/field.md) props.

### `Field.Error`

Accepts Base UI [`Field.Error`](https://base-ui.com/react/components/field.md) props.

### `Field.Control`

Accepts Base UI [`Field.Control`](https://base-ui.com/react/components/field.md) props.

### `Field.Item`

Accepts Base UI [`Field.Item`](https://base-ui.com/react/components/field.md) props.

### `Field.Validity`

Accepts Base UI [`Field.Validity`](https://base-ui.com/react/components/field.md) props.
