---
title: Field
description: Associate a control with its label, help, error, and inherited state.
package: moraine
version: 0.6.0
repository: https://github.com/subframe7536/moraine
---

# Field

> Associate a control with its label, help, error, and inherited state.

`Field` is a standalone presentational component with no form validation or form integration.
It is used only for rendering field UI, registering controls, inheriting state, and establishing ARIA relationships.

For form integration, use `form.Field` returned by `createForm()`.

## Basic usage

```tsx
import { Field, Input } from 'moraine'

export function Example() {
  return (
    <Field label="Email">
      <Input name="email" type="email" />
    </Field>
  )
}
```

## Anatomy

```text
Field [component; slot=root]
├── wrapper [slot]
│   ├── labelWrapper [slot]
│   │   ├── label [slot]
│   │   └── hint [slot]
│   └── description [slot]
└── container [slot]
    ├── help [slot]
    └── error [slot]
```

Help and error are mutually exclusive; the error replaces help when the field is invalid.

## Usage

Put a Moraine control inside `Field` so its label, description, and error IDs are registered with the actual focusable element. Standalone `Field` does not validate or submit values; use `form.Field` from `createForm()` when a schema owns the field. For local validation, pass the current message to `error`.

```tsx
import { Field, Input } from 'moraine'

export function FieldUsage() {
  return (
    <Field label="Email" description="We'll only use this for account notifications.">
      <Input name="email" placeholder="you@example.com" />
    </Field>
  )
}
```

### Visually hidden labels

Use `hiddenLabel` when a compact control needs an accessible name without a visible label.
It preserves the label association without reserving label spacing or an empty horizontal label column.
A non-empty `label` takes precedence over `hiddenLabel`. Hint and description text remain visible;
help and error text keep their usual placement.

```tsx
import { Field, Input } from 'moraine'

export function HiddenLabel() {
  return (
    <div class="flex flex-col gap-4">
      <Field hiddenLabel="Filter commands" help="Search by command name or keyboard shortcut.">
        <Input placeholder="Filter commands…" />
      </Field>
      <Field
        hiddenLabel="Command prefix"
        orientation="horizontal"
        error="Enter a prefix that starts with a letter and contains no spaces."
      >
        <Input placeholder="Command prefix…" />
      </Field>
    </div>
  )
}
```

For a switch with a trailing visible label, use `<Switch label="Auto refresh" />`.

## Examples

### Inherited state

```tsx
import { Field, Switch } from 'moraine'

export function InheritedState() {
  return (
    <Field label="Notifications" size="sm" required>
      <Switch label="Email alerts" />
    </Field>
  )
}
```

### Manual validation

```tsx
import { Field, Input } from 'moraine'
import { createSignal } from 'solid-js'

export function ManualValidation() {
  const [error, setError] = createSignal<string | false>()
  return (
    <Field label="Username" error={error()}>
      <Input onValueChange={(value) => setError(value ? false : 'Username is required')} />
    </Field>
  )
}
```

### Horizontal layout

```tsx
import { Field, Input } from 'moraine'

export function HorizontalLayout() {
  return (
    <Field orientation="horizontal" label="Display name" description="Shown to other users.">
      <Input />
    </Field>
  )
}
```

## Attributes

| Attributes | Slot | Description |
| --- | --- | --- |
| `data-required` | `field-label` | Present when the field input is required. |
| `data-has-text` | `field-container` | Present when the control currently contains text. |

## Props

Props for the Field component.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| description | JSX.Element \| undefined | — | Description text shown below the label. |
| disabled | boolean \| undefined | — | Whether controls inherit a disabled state. |
| error | JSX.Element \| undefined | — | Custom error message or force error state. |
| help | JSX.Element \| undefined | — | Help text shown below the control when no error is present. |
| hiddenLabel | string \| undefined | — | Visually hidden label used when no non-empty visible label is provided. |
| hint | JSX.Element \| undefined | — | Hint text shown near the label. |
| id | string \| undefined | — | Unique identifier for the field. |
| label | JSX.Element \| undefined | — | Label for the field. |
| name | Name \| undefined | — | Optional standalone field name. |
| orientation | 'vertical' \| 'horizontal' \| undefined | 'vertical' | Visual layout direction. |
| readOnly | boolean \| undefined | — | Whether controls inherit a read-only state. |
| required | boolean \| undefined | false | Whether the field is required. |
| size | 'sm' \| 'md' \| 'lg' \| undefined | 'md' | Visual size of the component. |
| as | T \| undefined | 'div' | The HTML element or component to render as. |
| children | JSX.Element \| ((props: RenderProps) => JSX.Element) \| undefined | — | Content or render function receiving the field state. |
| class | SlotClassValue \| undefined | — | Class applied to the component root or trigger element. |
| classes | Classes \| undefined | — | Family slot class defaults for this instance. |
| style | SlotStyleValue \| undefined | — | Style applied to the component root or trigger element. |
| styles | Styles \| undefined | — | Family slot style defaults for this instance. |
