# Input

A single-line text box, for text, numbers, addresses and files.

- **Import:** `import { Input } from "@booleanpress/ui/input"`
- **Page:** <https://ui.booleanpress.com/components/input> · @booleanpress/ui 0.1.0

## Usage

`Input` is a styled native `input`. Give it a visible name with a `Label` whose `htmlFor` is the input's `id`, or wrap the pair in a `Field`.

```tsx
import { Input } from "@booleanpress/ui/input"
import { Label } from "@booleanpress/ui/label"

export function SenderEmail() {
  return (
    <div className="flex flex-col gap-2">
      <Label htmlFor="sender-email">Sender email</Label>
      <Input id="sender-email" type="email" />
    </div>
  )
}
```

It takes every attribute of a native `input`. It is uncontrolled with `defaultValue`, or controlled with `value` and `onChange`. Pick the `type` that gives the right keyboard and validation (`email`, `number`, `url`, `file`). For a secret use `PasswordInput`; to put an icon, a prefix or a button inside the box use `InputGroup`.

## Examples

### Basic

A labelled email input with a placeholder.

```tsx
import { Input } from "@booleanpress/ui/input"
import { Label } from "@booleanpress/ui/label"

export default function InputBasic() {
  return (
    <div className="flex w-full max-w-sm flex-col gap-2">
      <Label htmlFor="sender-email">Sender email</Label>
      <Input id="sender-email" type="email" placeholder="alerts@example.com" />
    </div>
  )
}
```

### File

`type="file"` styles the file button to match the text.

```tsx
import { Input } from "@booleanpress/ui/input"
import { Label } from "@booleanpress/ui/label"

export default function InputFile() {
  return (
    <div className="flex w-full max-w-sm flex-col gap-2">
      <Label htmlFor="contacts-file">Contacts file</Label>
      <Input id="contacts-file" type="file" accept=".csv" />
    </div>
  )
}
```

### Disabled and read-only

A read-only input can be focused and copied; a disabled one cannot, and is not submitted.

```tsx
import { Input } from "@booleanpress/ui/input"
import { Label } from "@booleanpress/ui/label"

export default function InputDisabled() {
  return (
    <div className="flex w-full max-w-sm flex-col gap-4">
      <div className="flex flex-col gap-2">
        <Label htmlFor="mailer-id">Mailer ID</Label>
        <Input id="mailer-id" defaultValue="mailer_8f3a2c" readOnly />
      </div>
      <div className="flex flex-col gap-2">
        <Label htmlFor="region">Region</Label>
        <Input id="region" defaultValue="eu-west-1" disabled />
      </div>
    </div>
  )
}
```

### Invalid

`aria-invalid` draws the error border; `aria-describedby` reads the error message with the name.

```tsx
import { Input } from "@booleanpress/ui/input"
import { Label } from "@booleanpress/ui/label"

export default function InputInvalid() {
  return (
    <div className="flex w-full max-w-sm flex-col gap-2">
      <Label htmlFor="smtp-host">SMTP host</Label>
      <Input id="smtp-host" defaultValue="smtp example com" aria-invalid aria-describedby="smtp-host-error" />
      <p id="smtp-host-error" className="text-sm text-destructive">
        Enter a host name such as smtp.example.com.
      </p>
    </div>
  )
}
```

## Accessibility

**Semantics.** A native `input`. A `type="text"` input has the `textbox` role; `email`, `number` and the others keep their own roles.

**Labels.** Name every input: a `Label` with `htmlFor`, or `aria-label` when no visible text fits. A placeholder is not a name. Put hints and errors in `aria-describedby`.

**Focus.** It is in the tab order unless it is disabled. The focus ring shows on keyboard focus.

**Known limits.**

- `aria-invalid` only changes the look and the announcement. Validation and the message are yours.

### Keyboard

| Key | Behaviour |
| --- | --- |

## API

### Input

Renders a `input` and passes it every other prop.

Every part takes `className`, merged with its defaults by `cn()`, and `ref`, which reaches the element it renders.

**Data attributes:** `data-slot="input"` (Input).

## Theming

The border is `--control`, at least 3:1 against the surface; the focus ring is `--ring` at 50 %; the invalid border and ring use `--destructive`. In the dark theme the fill is `--input` at 30 %.

| Token | Used for |
| --- | --- |
| `--control` | border |
| `--destructive` | border, focus ring |
| `--foreground` | text |
| `--input` | border, background |
| `--muted-foreground` | text |
| `--primary` | background |
| `--primary-foreground` | text |
| `--ring` | border, focus ring |
