# Input

> A single line of text: a name, an email address, a search.

- Import: `import { Input } from '@thekestongroup/ui'`
- Group: Form
- Live example: https://ui.keston.co/storybook/?path=/story/components-form-input--default
- Source: https://github.com/thekestongroup/ui/blob/main/src/components/Input/Input.vue

## When to use

- Short free text on one line: names, email addresses, IDs, search terms.

## When not to use

- Several lines of notes: use InputRichText.
- A number someone steps through (a year group, a quantity): use InputNumber.
- A date: use InputDate.
- A password: use InputPassword. A one-time code: use InputCode.
- Choosing from a list: use Select or RadioGroup.

## Anatomy

| Part | Required | Notes |
|---|---|---|
| label | Yes | 14px, above the box. Also the input's accessible name. |
| helper | No | 12px under the label, or behind a `?` (InfoTip) beside it. |
| box | Yes | FormField's box: like a medium basic Button, 38px tall, 4px corners, 12px / 8px padding. |
| leading / trailing | No | Slots either side of the text, e.g. a search or mail icon. Icons are 16px, 70% opacity. |
| input | Yes | 14px text (16px on touch screens). Placeholder black 55%. |
| message | No | Error, success or loading text that slides open under the box. |

## Properties

| Property | Type | Default | Description |
|---|---|---|---|
| modelValue | string | '' | The text. Use `v-model`. |
| label | string | — | Required. |
| helper / helperPlacement | string / below \| icon | — / below | Extra guidance, under the label or behind a `?`. |
| errorText | string | — | Error message, e.g. from a Zod schema. Overrides everything below. |
| status / statusText | error \| success \| loading / string | — | Colours the box and the message; `loading` shows a spinner, e.g. "Checking availability…". |
| minLength | number | — | Shows "Must be at least N characters" once the field has been left. |
| maxLength | number | — | Shows "Must be N characters or fewer" straight away. Typing isn't blocked. |
| disabled | boolean | false | 40% opacity, not editable. |

Attributes such as `type`, `name`, `placeholder` and `autocomplete` go to the `<input>`.

## States

| State | Appearance | Notes |
|---|---|---|
| Enabled | White box, black 15% border. | |
| Focused | Focus ring around the box. | |
| Error | Red border and message. | |
| Success | Green border and message. | |
| Loading | Spinner and message; border unchanged. | |
| Disabled | 40% opacity. | |

## Behaviour

- Pressing anywhere in the box, including its padding and icons, focuses the input.
- "Too short" waits until the field has been left once, so it doesn't complain while someone is still typing. "Too long" shows straight away.
- An error clears as soon as the value becomes valid.

## Content guidelines

- Label: a short noun phrase, e.g. "Email address", not a question.
- Put examples and rules in the helper, not the placeholder: placeholders vanish while typing.

## Accessibility

- The label is a real `<label>` for the input. Helper and message are its description (`aria-describedby`); the message is announced politely.
- Errors set `aria-invalid`.

## Platform adaptation

| Platform | Implementation | Differences |
|---|---|---|
| Web / desktop (Vue) | `Input.vue` | Built on FormField. |
| iOS (SwiftUI) | — | `TextField` with the label above; the right `textContentType` and keyboard. |
| Android (Compose) | — | `OutlinedTextField`-like field with the label above, not floating. |

## Tokens used

| Token | Used for |
|---|---|
| `color-focus` | Focus ring |
| `color-red` / `color-green` | Error / success |

## API (from the source)

The component's exact props, model, events, slots and types, with their documentation comments.

```ts
// Input.vue
export type InputStatus = FormFieldStatus

export interface InputProps {
  /** Visible label. Always set it: it is also the input's accessible name. */
  label: string
  /** Extra guidance about what to enter. */
  helper?: string
  /** Show helper text under the label, or behind a `?` icon next to it. */
  helperPlacement?: 'below' | 'icon'
  /**
   * Error message, e.g. from a Zod / VeeValidate schema. When set (and not
   * empty) the field shows as an error with this text; leave it undefined
   * when the value is valid. Overrides `status`, `statusText` and the length
   * check.
   */
  errorText?: string
  /** Colours the field and the status text. Overrides the length check. */
  status?: InputStatus
  /** Message under the field, e.g. why the value is invalid. */
  statusText?: string
  /** Shows an error once the user leaves a field that is too short. */
  minLength?: number
  /** Shows an error as soon as the value is too long. Typing is not blocked. */
  maxLength?: number
  disabled?: boolean
  class?: HTMLAttributes['class']
}

const model = defineModel<string>({ default: '' })
```
