---
title: Field
description: "Groups a label, form control, description, and validation message."
order: 14
tags: [components]
---

import { Preview } from "$lib/components/preview";
import { Field, Input, Textarea } from "areia";

# Field

Groups a label, form control, description, and validation message. `Field` wires accessible relationships and tracks focused, filled, dirty, touched, valid, and invalid states.

[Source Code](https://github.com/ilhajs/areia/blob/main/packages/areia/src/components/field/index.ts)

<Preview
  code={
    'import ilha from "ilha";\nimport { Field, Input } from "areia";\n\nexport default ilha.render(() => (\n  <Field label="Email" description="Use your work email.">\n    <Input\n      data-slot="field-control"\n      type="email"\n      name="email"\n      placeholder="you@example.com"\n    />\n  </Field>\n));'
  }
  lang="tsx"
>
  <div class="w-full max-w-sm">
    <Field label="Email" description="Use your work email.">
      <Input
        data-slot="field-control"
        type="email"
        name="email"
        placeholder="you@example.com"
      />
    </Field>
  </div>
</Preview>

## Import

```ts
import { Field } from "areia";
```

## Usage

Render a control with `data-slot="field-control"` inside `Field`. The controller associates `Field.Label`, `Field.Description`, and `Field.Error` with the control.

<Preview
  code={
    'import ilha from "ilha";\nimport { Field, Input } from "areia";\n\nexport default ilha.render(() => (\n  <Field\n    label="Username"\n    description="This will be visible on your profile."\n  >\n    <Input\n      data-slot="field-control"\n      name="username"\n      placeholder="ryuz"\n    />\n  </Field>\n));'
  }
  lang="tsx"
>
  <div class="w-full max-w-sm">
    <Field
      label="Username"
      description="This will be visible on your profile."
    >
      <Input
        data-slot="field-control"
        name="username"
        placeholder="ryuz"
      />
    </Field>
  </div>
</Preview>

## Examples

### Required Field

Native constraint validation is read from the field control.

<Preview
  code={
    'import ilha from "ilha";\nimport { Field, Input } from "areia";\n\nexport default ilha.render(() => (\n  <Field label="Project name" error="Project name is required.">\n    <Input\n      data-slot="field-control"\n      name="project"\n      required\n      placeholder="My app"\n    />\n  </Field>\n));'
  }
  lang="tsx"
>
  <div class="w-full max-w-sm">
    <Field
      label="Project name"
      error="Project name is required."
    >
      <Input
        data-slot="field-control"
        name="project"
        required
        placeholder="My app"
      />
    </Field>
  </div>
</Preview>

### Custom Validation

Return a string from `validate` to mark the field invalid. Use `Field.Root` when you need island props such as `validate`.

<Preview
  code={
    'import ilha from "ilha";\nimport { Field, Input } from "areia";\n\nexport default ilha.render(() => (\n  <Field.Root\n    label="Email"\n    error="Enter a valid email address."\n    validationMode="onBlur"\n    validate={(value) =>\n      value.includes("@")\n        ? null\n        : "Enter a valid email address."\n    }\n  >\n    <Input\n      data-slot="field-control"\n      type="email"\n      name="email"\n      placeholder="you@example.com"\n    />\n  </Field.Root>\n));'
  }
  lang="tsx"
  codeOnly
/>

### Invalid State

Use `invalid` when validity is controlled by server state or another external source.

<Preview
  code={
    'import ilha from "ilha";\nimport { Field, Input } from "areia";\n\nexport default ilha.render(() => (\n  <Field\n    label="Workspace slug"\n    invalid\n    error="This slug is already taken."\n  >\n    <Input\n      data-slot="field-control"\n      name="slug"\n      value="areia"\n    />\n  </Field>\n));'
  }
  lang="tsx"
>
  <div class="w-full max-w-sm">
    <Field
      label="Workspace slug"
      invalid
      error="This slug is already taken."
    >
      <Input
        data-slot="field-control"
        name="slug"
        value="areia"
      />
    </Field>
  </div>
</Preview>

### Composed Parts

Use the part helpers when you need a custom layout.

<Preview
  code={
    'import ilha from "ilha";\nimport { Field, Textarea } from "areia";\n\nexport default ilha.render(() => (\n  <Field>\n    <Field.Label label="Description" />\n    <Textarea\n      data-slot="field-control"\n      name="description"\n      placeholder="Describe your project..."\n    />\n    <div class="flex items-center justify-between gap-3">\n      <Field.Description description="Keep it concise." />\n      <Field.Error error="Description is required." />\n    </div>\n  </Field>\n));'
  }
  lang="tsx"
>
  <div class="w-full max-w-sm">
    <Field>
      <Field.Label label="Description" />
      <Textarea
        data-slot="field-control"
        name="description"
        placeholder="Describe your project..."
      />
      <div class="flex items-center justify-between gap-3">
        <Field.Description description="Keep it concise." />
        <Field.Error error="Description is required." />
      </div>
    </Field>
  </div>
</Preview>

## API

### `Field(input)`

| Prop             | Type                                             | Default      | Description                                 |
| ---------------- | ------------------------------------------------ | ------------ | ------------------------------------------- |
| `label`          | `unknown`                                        | —            | Label content.                              |
| `description`    | `unknown`                                        | —            | Help text associated with the control.      |
| `error`          | `unknown`                                        | —            | Error text shown when the field is invalid. |
| `children`       | `unknown`                                        | —            | Field control and custom content.           |
| `name`           | `string`                                         | control name | Field name.                                 |
| `disabled`       | `boolean`                                        | `false`      | Disables the field.                         |
| `invalid`        | `boolean`                                        | `false`      | Forces invalid state.                       |
| `validationMode` | `"onBlur" \| "onChange" \| "onSubmit"`           | `"onBlur"`   | When validation runs.                       |
| `validate`       | `(value, control) => string \| string[] \| null` | —            | Custom validator (`Field.Root` island).     |

## Slots

`Field` uses these data slots:

- `field`
- `field-label`
- `field-control`
- `field-description`
- `field-error`
- `field-validity`
- `field-item`

State attributes are applied to the root and parts:

- `data-disabled`
- `data-focused`
- `data-filled`
- `data-dirty`
- `data-touched`
- `data-valid`
- `data-invalid`
