# Input

A field for one line of text.

```tsx
import { Field, Input } from 'ferry-ui'

export default function InputHero() {
  return (
    <Field label="Project name" hint="The name shows in the list of projects." className="w-full max-w-sm">
      <Input placeholder="Billing portal" />
    </Field>
  )
}
```

## Usage guidelines

- **One line of text.** For text on more than one line, use [Textarea](/docs/components/textarea).
- **A list of options is not an input.** For a value from a fixed list, use [Select](/docs/components/select).
- **Give each input a label.** Use [Field](/docs/components/field), a [Label](/docs/components/label) or `aria-label`.
- **A search field has its own component.** To filter a list, use the `SearchInput` of [List Toolbar](/docs/components/list-toolbar).

## Anatomy

Import the component. An input has one part.

```tsx title="Anatomy"

<Input />
```

## Examples

### Label

Give the same value to the `htmlFor` of the `Label` and to the `id` of the input.

`Field` adds the label, the hint and the error message for you.

```tsx
import { Input, Label } from 'ferry-ui'

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

### Sizes

The `size` prop sets the height. The default is `md`.

```tsx
import { Input } from 'ferry-ui'

export default function InputSizes() {
  return (
    <div className="flex w-full max-w-sm flex-col gap-3">
      <Input size="tiny" placeholder="Tiny, 26px" aria-label="Tiny input" />
      <Input size="sm" placeholder="Small, 30px" aria-label="Small input" />
      <Input size="md" placeholder="Medium, 34px" aria-label="Medium input" />
      <Input size="lg" placeholder="Large, 38px" aria-label="Large input" />
    </div>
  )
}
```

| Size | Height | Use |
| --- | --- | --- |
| `tiny` | 26px | Toolbars and table cells. |
| `sm` | 30px | Filters and dense forms. |
| `md` | 34px | Form fields. |
| `lg` | 38px | Sign-in forms. |

### Input and button

The heights are the same as the heights of [Button](/docs/components/button). Give the same `size` to the input and to the button.

The default size of a button is `sm`. The default size of an input is `md`.

```tsx
import { Button, Input } from 'ferry-ui'

export default function InputWithButton() {
  return (
    <div className="flex w-full max-w-sm gap-2">
      <Input size="sm" type="email" placeholder="maya@example.com" aria-label="Email of the new member" />
      <Button size="sm" variant="primary">
        Invite
      </Button>
    </div>
  )
}
```

### Monospace

Set `mono` for a value that a program reads: an identifier, a slug, a URL or a key.

```tsx
import { Field, Input } from 'ferry-ui'

export default function InputMono() {
  return (
    <Field label="Webhook URL" hint="The app sends each event to this address." className="w-full max-w-sm">
      <Input mono type="url" placeholder="https://example.com/webhooks" />
    </Field>
  )
}
```

### States

`disabled` makes the input unavailable. `readOnly` shows a value that the user can copy but not change.

`aria-invalid` shows the error border. `Field` sets it when you pass `error`.

```tsx
import { Field, Input } from 'ferry-ui'

export default function InputStates() {
  return (
    <div className="flex w-full max-w-sm flex-col gap-5">
      <Field label="Workspace" hint="Only an owner can change the name.">
        <Input disabled defaultValue="Acme" />
      </Field>
      <Field label="Project ID">
        <Input readOnly mono defaultValue="prj_8f2k1m9x" />
      </Field>
      <Field label="Billing email" error="Enter a valid email address.">
        <Input type="email" defaultValue="maya@example" />
      </Field>
    </div>
  )
}
```

### Controlled value

An input holds its value by default. Use `defaultValue` for the first value.

To control the value, pass `value` and `onChange`.

```tsx
import * as React from 'react'
import { Field, Input } from 'ferry-ui'

export default function InputControlled() {
  const [name, setName] = React.useState('Billing portal')
  const slug = name
    .trim()
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, '-')

  return (
    <Field label="Project name" hint={`Slug: ${slug === '' ? 'none' : slug}`} className="w-full max-w-sm">
      <Input value={name} onChange={(event) => setName(event.target.value)} />
    </Field>
  )
}
```

### Input look on another element

`inputVariants` returns the classes of `Input`. Use it for an element that cannot be an `<input>`.

An element that is not an input gets the read-only background.

```tsx
import * as React from 'react'
import { Input, Label, inputVariants } from 'ferry-ui'

const SEAT_PRICE = 20

export default function InputVariantsHelper() {
  const [seats, setSeats] = React.useState('12')
  const total = (Number(seats) || 0) * SEAT_PRICE

  return (
    <div className="flex w-full max-w-sm flex-col gap-2">
      <Label htmlFor="plan-seats">Seats</Label>
      <div className="flex gap-2">
        <Input
          id="plan-seats"
          type="number"
          size="sm"
          min={1}
          className="w-24"
          value={seats}
          onChange={(event) => setSeats(event.target.value)}
        />
        <output
          htmlFor="plan-seats"
          aria-label="Monthly total"
          className={inputVariants({ size: 'sm', mono: true, className: 'flex items-center' })}
        >
          ${total}.00 / month
        </output>
      </div>
    </div>
  )
}
```

## Accessibility

- A placeholder is not a label. Each input must have an accessible name.
- Show each error as text. Color alone is not sufficient.
- Link the hint and the error message to the input with `aria-describedby`. `Field` does this for you.

## API reference

`Input` also accepts each attribute of the `<input>` element. The numeric `size` attribute is not available.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `size` | `"tiny" \| "sm" \| "md" \| "lg"` | `md` | Control height, matched to Button sizes so fields and buttons line up in a row: `tiny` 26px (toolbars, table cells), `sm` 30px (filters, dense forms), `md` 34px (default form field), `lg` 38px (sign-in / hero forms). |
| `mono` | `boolean` | `false` | Monospace face at 13px. Use for machine values the user types or copies (identifiers, slugs, URLs, keys, hashes); keep prose fields in the sans face. |

### inputVariants

`inputVariants(options)` returns a string of classes.

| Option | Type | Role |
| --- | --- | --- |
| `size` | `tiny`, `sm`, `md` or `lg` | The height. The default is `md`. |
| `mono` | `boolean` | The monospace font. The default is `false`. |
| `className` | `string` | More classes for the element. |
