# Controls & fields
Every form widget. Read [Concepts → Control vs Field](./concepts.md#control-vs-field--the-key-distinction)
first if you haven't — it explains the two tiers. In short:
- **`*Field`** = captioned form row (label + control + description/info/validation).
Put these in a `Section`.
- **`*Control`** = the bare widget. Place it yourself (toolbar, custom layout).
Remember the convention: **`value` is an accessor** (`() => V`), `onChange` is
`(next: V) => void`. With [`createEditorStore`](./state.md), `{...bind('path')}`
fills both in.
---
## Shared props
### Every `*Field` accepts
| Prop | Type | Notes |
|---|---|---|
| `name` | `string` | The caption. `""` renders no label, and the value spans the row. Pass `aria-label` then, since no caption names the control. |
| `value` | `() => V` | Value accessor. |
| `onChange` | `(next: V) => void` | Fires only for a user's edit, never on mount or when your code changes `value`. See [when it fires](./guides.md#reactive-values-and-change-events). |
| `readonly?` | `() => boolean` | Locks the field (see [Readonly](#readonly)). |
| `layout?` | `'compact' \| 'expanded'` | Row layout (see [Layout](#layout-compact-vs-expanded)). Some fields pin one. |
| `description?` | `string` | A muted help line under the control. |
| `info?` | `string \| (() => string)` | Shows an info `(i)` bubble beside the caption. |
| `id?` | `string` | Deep-link handle for [`focusField(id)`](./guides.md#deep-linking-to-a-field). |
| `validate?` | `(v: V) => ValidationResult \| null` | See [validation](./guides.md#validation--tooltips). |
Text-based fields (`TextField`, `TextareaField`) also take `minLength?`,
`maxLength?`, `pattern?: RegExp` (built-in validation helpers).
### Every `*Control` accepts
| Prop | Type | Notes |
|---|---|---|
| `value` | `() => V` | Value accessor. |
| `onChange` | `(next: V) => void` | Commit handler. |
| `readonly?` | `() => boolean` | Locks the control. |
| `aria-label?` | `string` | Accessible name (a field forwards its caption here). |
| `level?` | `'error' \| 'warn'` | Recolours the border (validation cue). |
| `onFocusIn?` / `onFocusOut?` / `onPointerEnter?` | event handlers | Validation/tooltip wiring; spread `{...v.controlHandlers}` from `createFieldValidation`. |
A control renders **only the widget** — no caption, no row. It emits the same CSS
classes the field uses, so theming is shared.
### Text inputs also accept
The five text-input fields/controls (`Text`, `Number`, `Textarea`, `Color`,
`Search`) take:
| Prop | Type | Notes |
|---|---|---|
| `touchSizing?` | `boolean` | On touch devices, render the input at 16px so focusing it doesn't trigger iOS Safari's zoom (it zooms any focused input under 16px). Default `true`. Set `false` to opt out — the input keeps its tier font and may zoom. Font-only: the row height and other controls are unaffected, and it has no effect on non-touch devices or the `small` tier (see [Theming](./theming.md#size-tiers)). |
All five also opt out of browser text assistance: no spellcheck, autocorrect,
auto-capitalization or autofill. Editor values are names, ids, paths and code,
not prose, so these only get in the way (and on mobile, autocorrect rewrites the
value as you type). This is fixed, not a prop.
The single-line inputs (`Text`, `Number`, `Color`, `Search`) treat Enter as
"done", never a newline. The on-screen key reads **Done** (**Go** for Search).
When the edit started from a touch or pen press, Enter releases focus, which
closes the on-screen keyboard. With a mouse or keyboard, Text and Number keep
focus on Enter, so Tab carries on as usual. Color always releases focus on Enter,
since Enter also closes its picker. Textarea keeps Enter as a newline.
---
## Value fields & controls
### Text — `TextField` / `TextControl`
Single-line text input.
```tsx
```
| Extra prop | Type | Notes |
|---|---|---|
| `placeholder?` | `string` | |
| `minLength?` / `maxLength?` | `number` | Built-in validation. |
| `pattern?` | `RegExp` | Built-in validation. |
| `actions?` | `InputAction[]` | Buttons attached to the input's right edge (see below). |
**Attached action buttons (`actions`).** Seam a row of buttons flush to the
input's right edge — a copy / apply / reset action. Each `InputAction` is an icon
*or* a text `label`, with a `title` (shown as a tooltip on hover and keyboard focus, and used as its
`aria-label`), an `onClick`, and an optional reactive `disabled`. They're real `