<!-- Protocore Design System — Input -->
# Input

- **Category:** Inputs (`inputs`)
- **Slug:** `inputs/input`
- **Status:** stable
- **Platforms:** web, mobile
- **Import:** `import { Input } from "@protocore/pds";`
- **Docs:** https://pds.protocore.io/components/inputs/input

> The base single-line text control — a sunken field with optional leading and trailing adornment slots.

## When to use

**Input** is the base for single-line free text — names, hostnames, URLs, tokens. Almost always wrap it in a **Field** for its label, hint, and error wiring.

Reach for a specialised sibling when the shape fits:

- **NumberInput** — numeric values with a stepper and min/max/step.
- **SearchInput** — a query box with a magnifier and clear button.
- **Textarea** — multi-line text.
- **Select** / **Combobox** — choosing from a known set rather than typing free text.

## Mobile (React Native)

**Preview.** `@protocore/pds-mobile` ships the React Native sibling of **Input**. It mirrors the web API where React Native allows; the package is a **preview** with no device-level QA yet, so pin it and expect small changes.

Import it from the mobile package (not `@protocore/pds`), inside a `<PdsProvider>` — there is no stylesheet, so `style` (a `ViewStyle`) replaces `className` and every value comes from the theme:

```tsx
import { Input } from "@protocore/pds-mobile";
```

**Parity with web.** The sunken single-line text control, wrapping RN `TextInput` (web wraps `<input>`).

- Use `onChangeText` (RN) instead of `onChange`.
- The border goes `border-ctrl` → `accent` on focus and `danger` when `invalid`; `invalid` also sets `accessibilityState.invalid`.
- `startAdornment` / `endAdornment` render muted slots inside the field.

```tsx
<Input
  size="md"
  placeholder="Service name"
  value={name}
  onChangeText={setName}
/>
```

## Props

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `className` | `string` | no | — | — |
| `endAdornment` | `ReactNode` | no | — | Trailing slot (muted; mono for glyph/unit labels), rendered inside the field. |
| `invalid` | `boolean` | no | — | Mark the field invalid — danger border plus `aria-invalid`. |
| `size` | `enum` | no | `md` | Control height: `sm` (32) · `md` (36, default) · `lg` (40). |
| `startAdornment` | `ReactNode` | no | — | Leading slot (muted; mono for glyph/unit labels), rendered inside the field. |
| `style` | `CSSProperties` | no | — | — |

## Examples

### Basics

A sunken, sharp-cornered text field whose border turns to `--pds-accent` on focus. Spread any native `<input>` attribute (`type`, `value`, `onChange`, `placeholder`…) straight through.

```tsx
import { Field, Input } from "@protocore/pds";

export default function Basics() {
  // Wrap the control in a Field so it carries a real, associated label —
  // the accessible baseline for every form input.
  return (
    <Field label="Service name" hint="Lowercase, hyphen-separated." style={{ maxWidth: 320 }}>
      <Input placeholder="ledger-indexer" />
    </Field>
  );
}
```

### Sizes

Three heights: `sm` (32), `md` (36, default), and `lg` (40). Match the Input size to the buttons it sits beside.

```tsx
import { Input } from "@protocore/pds";

export default function Sizes() {
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 12, maxWidth: 320 }}>
      <Input aria-label="Small input" size="sm" placeholder="Small (32)" />
      <Input aria-label="Medium input" size="md" placeholder="Medium (36)" />
      <Input aria-label="Large input" size="lg" placeholder="Large (40)" />
    </div>
  );
}
```

## Do & don't

**Do**

- Wrap Input in a Field so it carries a label and hint.
- Use adornments for static units or glyphs ($, ms, https://).
- Set the right native type (email, url, tel) so mobile keyboards adapt.
- Pair invalid with a Field error that explains the problem.

**Don't**

- Don't ship an Input with no associated label (Field or an explicit <label>).
- Don't put buttons or links inside an adornment slot — they're decorative.
- Don't use Input for numbers that need stepping — use NumberInput.
- Don't convey invalid with the red border alone; add a message.

## Accessibility

**Notes**

- Renders a native `<input>`; give it a label via Field or a wrapping `<label>`.
- `invalid` sets `aria-invalid`; describe the error with Field's `error` text.
- The start adornment is `aria-hidden`; put any meaning users need into the label or value.
- Focus is a visible accent border plus the shared focus ring — never suppressed.

## Related

`field`, `textarea`, `number-input`, `search-input`

---

© Protocore. All rights reserved. Use of the Protocore Design System requires prior written authorization from Protocore (contact@protocore.io). These machine-readable materials must not be ingested into ML-training datasets or derivative design systems. See https://pds.protocore.io/legal/
