# Field

What the user types or picks in a form. The intent decides the element (`<input>`, `<textarea>`, `<select>`) and sets `type`, `inputMode` and `autoComplete`.

Renders: `input` `textarea` `select` · Intents: [14](#intents-it-renders) · Domains: [`field.*`](https://www.prongs.dev/docs/intents/field.md)

## Examples

### A labelled field with a hint

The label is a [`text.label`](https://www.prongs.dev/docs/intents/text/label.md) rendered as `<label>`. The intent sets `type`, `inputMode` and `autoComplete`.

```tsx
<Layout intent="layout.field" className="w-full max-w-sm">
  <Text intent="text.label" as="label" htmlFor="example-email">Email</Text>
  <Field intent="field.email" id="example-email" placeholder="you@example.com" aria-describedby="example-email-hint" />
  <Text intent="text.caption" id="example-email-hint">Only used for signing in.</Text>
</Layout>
```

### An error

`aria-invalid` marks the field; the message is a [`feedback.error`](https://www.prongs.dev/docs/intents/feedback/error.md) under it.

```tsx
<Layout intent="layout.field" className="w-full max-w-sm">
  <Text intent="text.label" as="label" htmlFor="example-handle">Handle</Text>
  <Field intent="field.text" id="example-handle" defaultValue="ada" aria-invalid aria-describedby="example-handle-error" />
  <Text intent="feedback.error" id="example-handle-error">That handle is taken.</Text>
</Layout>
```

### A list to pick from

[`field.select`](https://www.prongs.dev/docs/intents/field/select.md) renders a `<select>`; the options are its children.

```tsx
<Layout intent="layout.field" className="w-full max-w-sm">
  <Text intent="text.label" as="label" htmlFor="example-zone">Time zone</Text>
  <Field intent="field.select" id="example-zone" defaultValue="Europe/London">
    <option>America/New_York</option>
    <option>Europe/London</option>
    <option>Asia/Tokyo</option>
  </Field>
</Layout>
```

### Several lines

[`field.multiline`](https://www.prongs.dev/docs/intents/field/multiline.md) renders a `<textarea>`.

```tsx
<Field intent="field.multiline" aria-label="Bio" rows={3} placeholder="A few words about you" width="full" />
```

## Intents it renders

One domain, with its own page of neighbours and examples. The intent decides the element; these are the starter intents.

### Field [`field.*`](https://www.prongs.dev/docs/intents/field.md)

14 intents

| Intent | Use it for | Resolves to |
|---|---|---|
| [`field.text`](https://www.prongs.dev/docs/intents/field/text.md) | Short free text on one line: names, titles, handles | `<input type="text">` |
| [`field.email`](https://www.prongs.dev/docs/intents/field/email.md) | An email address | `<input type="email">` |
| [`field.password`](https://www.prongs.dev/docs/intents/field/password.md) | A password, with room for a show/hide control. Set autoComplete="new-password" when creating one | `<input type="password">` |
| [`field.password.shown`](https://www.prongs.dev/docs/intents/field/password-shown.md) | A password field while its content is revealed | `<input type="text">` |
| [`field.search`](https://www.prongs.dev/docs/intents/field/search.md) | The main search of a page: find people, products, anything | `<input type="search">` |
| [`field.filter`](https://www.prongs.dev/docs/intents/field/filter.md) | Narrows a list that is already shown, usually in a toolbar: "Search this feed" | `<input type="search">` |
| [`field.number`](https://www.prongs.dev/docs/intents/field/number.md) | A quantity or amount | `<input type="number">` |
| [`field.range`](https://www.prongs.dev/docs/intents/field/range.md) | A value picked by sliding along a scale: volume, a playback position, a price limit. Give it min, max, value and an aria-label | `<input type="range">` |
| [`field.url`](https://www.prongs.dev/docs/intents/field/url.md) | A full web address | `<input type="url">` |
| [`field.multiline`](https://www.prongs.dev/docs/intents/field/multiline.md) | Longer free text over several lines: bios, messages, notes | `<textarea>` |
| [`field.checkbox`](https://www.prongs.dev/docs/intents/field/checkbox.md) | A yes/no choice that is sent with a form: remember me, agree to terms. Pair with a text.label | `<input type="checkbox">` |
| [`field.switch`](https://www.prongs.dev/docs/intents/field/switch.md) | A setting that turns on or off immediately: show images, compact mode. Pair with a text.label | `<input type="checkbox">` |
| [`field.select`](https://www.prongs.dev/docs/intents/field/select.md) | One value from a list too long to show as options: country, time zone. Children are <option>s | `<select>` |
| [`field.color`](https://www.prongs.dev/docs/intents/field/color.md) | Any colour, picked with the system colour picker | `<input type="color">` |

## Props

Plus its element’s usual attributes (`id`, `onClick`, `aria-*`, `data-*`) and the shared layout props below. No `className` or `style`.

| Prop | Type | What it does |
|---|---|---|
| `intent` (required) | `FieldIntent` | What is being entered: [`field.email`](https://www.prongs.dev/docs/intents/field/email.md), [`field.password`](https://www.prongs.dev/docs/intents/field/password.md), [`field.multiline`](https://www.prongs.dev/docs/intents/field/multiline.md)... |
| `label` | `ReactNode` | The label. With it, Field renders the whole [`layout.field`](https://www.prongs.dev/docs/intents/layout/field.md): label, field, hint and error, connected for screen readers. |
| `hint` | `ReactNode` | Help under the field ([`text.caption`](https://www.prongs.dev/docs/intents/text/caption.md)). Needs `label`. |
| `error` | `ReactNode` | What is wrong with the value ([`feedback.error`](https://www.prongs.dev/docs/intents/feedback/error.md)). Marks the field invalid. Needs `label`. |
| `rows` | `number` | Height of a multiline field, in lines. |
| `children` | `ReactNode` | For select fields: the `<option>`s. |
| `ref` | `Ref<HTMLInputElement>` | Reaches the underlying element. |
| `unsafeClassName` | `string` | Bypasses the intent. Needs a `// prongs-unsafe: <reason>` comment on the line above, and `prongs check` counts it. |

### Layout props

Where the element sits, never how it looks. Spacing between elements comes from the parent [`<Layout>`](https://www.prongs.dev/docs/components/layout.md).

| Prop | Type | What it does |
|---|---|---|
| `align` | `'start' \| 'center' \| 'end'` | On text, the text alignment. On anything else, pushes it to that end of its row or column. |
| `width` | `'auto' \| 'full' \| 'prose' \| 'sm' \| 'md' \| 'lg'` | Full width, or a maximum width. |
| `hideBelow` | `'sm' \| 'md' \| 'lg'` | Hidden on screens narrower than this breakpoint. |
| `showBelow` | `'sm' \| 'md' \| 'lg'` | Shown only on screens narrower than this breakpoint. |
| `truncate` | `boolean` | One line, cut off with an ellipsis. |
| `nowrap` | `boolean` | Keeps the text on one line. |

## Rules

- Do not pass `type`: the intent sets it.
- Label it with `label` (plus `hint` and `error`), which renders and wires the whole field; or give it an `aria-label` when the label is visible elsewhere, like a search box.
- It takes the usual input attributes: `value`, `onChange`, `name`, `placeholder`, `required`...
