# TextField

> Slug: `text-field` · Category: Form Controls

## When to use

- Single-line free-text input (name, email, phone, URL, search query, plain text).
- Use the floating-label pattern for any short text entry. Use `type` to switch HTML semantics (`text` | `email` | `tel` | `number` | `url` | `search` | `password`).

## When NOT to use

- Multi-line input — use `TextArea`.
- Password entry — use `PasswordField` (handles the visibility toggle).
- Credit card numbers — use `CreditCardInput` (adds the leading card icon).
- Search-as-you-type with a clear affordance — use `Search`.
- Combobox-style inputs inside a menu — use `SearchingInput` or `TextingInput`.

## Variants & decision tree

| Need | Use |
|---|---|
| Plain text | `<TextField type="text" />` |
| Email | `<TextField type="email" inputMode="email" />` |
| Phone | `<TextField type="tel" inputMode="tel" />` |
| Numeric | `<TextField type="number" inputMode="numeric" />` |
| Trailing icon/button | pass `trailingDecoration` + `trailingButtonLabel` |

## States

Empty, focused, filled (label floats), error (`errorMessage`), disabled, read-only, required (asterisk).

## Props

| Prop | Type | Default | Description |
|---|---|---|---|
| `id` | `string` | — | Required. Links label to input. |
| `label` | `string` | — | Required. Floating label text. |
| `name` | `string` | — | Required for form submission. |
| `value` | `string` | — | Controlled value. |
| `defaultValue` | `string` | — | Uncontrolled initial value. |
| `onChange` | `ChangeEventHandler` | — | Standard React change handler. |
| `type` | `InputTypes` | `'text'` | HTML input type. |
| `inputMode` | `InputModes` | `'text'` | Mobile keyboard hint. |
| `errorMessage` | `string` | — | Sets `aria-invalid` and shows error text. |
| `supportingText` | `string` | — | Helper text below the input. |
| `disabled` | `boolean` | `false` | Disables the input. |
| `readOnly` | `boolean` | `false` | Read-only input. |
| `required` | `boolean` | `false` | Adds asterisk and `required`. |
| `inverse` | `boolean` | `false` | Dark-background styling. |
| `maxLength` | `number` | — | Max characters. |
| `trailingDecoration` | `ReactNode` | — | Trailing icon/button slot. |
| `trailingButtonLabel` | `string` | — | a11y label for trailing button. |

## Usage examples

```tsx
// Controlled
const [email, setEmail] = useState('');
<TextField
  id="email"
  name="email"
  label="Email address"
  type="email"
  value={email}
  onChange={(e) => setEmail(e.target.value)}
  required
/>

// Uncontrolled with helper text
<TextField id="user" name="user" label="Username" defaultValue="" supportingText="6+ characters" />

// Error state
<TextField id="phone" name="phone" label="Phone" type="tel" errorMessage="Enter a 10-digit number" />
```

## Composition

Pair inside a `<form>` with `Button` and other inputs (see `patterns.md`). Inverse-aware inside dark sections under `ArrowThemeProvider inverse`.

## Accessibility

`id`, `label`, and `name` are required for screen reader and form behavior. Do NOT wrap in an extra `<label>` — Arrow renders the `<label htmlFor={id}>` internally. `errorMessage` automatically wires `aria-invalid` + `aria-describedby`. Avoid `placeholder` for instructions; use `label` and `supportingText`.

## Do / Don't

- DO use `type="email"`, `type="tel"`, `type="number"` so mobile keyboards adapt.
- DO use `errorMessage` for inline validation.
- DON'T use `placeholder` as a label substitute.
- DON'T render a separate `<label>` element around it.
