---
id: "packages/active-ui/input"
title: "Input and Textarea"
description: "A single line of text and a block of text that grows with its content, with the shared look of every text control."
url: "/packages/active-ui/input"
locale: "en"
revision: "14a64b1f0b198bce"
---

# Input and Textarea

`Input` is a text field of one line, `Textarea` one of several lines. Both take every attribute of
their element (`type`, `value`, `maxLength`, `autoComplete`) and add only the look that every text
control of the package shares: the fill, the border, focus and the error state. Put each in a
[Field](/packages/active-ui/field), which gives it a label, a description and an error.

**Example: Single line, states, file and a growing textarea**

Client: Runs entirely in your browser. Source: `examples/ui/input.tsx`.

```tsx
// apps/docs/examples/ui/input.tsx
'use client';

import {useState} from 'react';

import {
  Field,
  FieldDescription,
  FieldError,
  FieldLabel,
} from '@workspace/active-ui/components/primitives/field';
import {Input} from '@workspace/active-ui/components/primitives/input';
import {Textarea} from '@workspace/active-ui/components/primitives/textarea';

const LIMIT = 280;

/**
 * Text input in its common forms, each inside a `Field` that labels it: a
 * single line, a disabled one, one in the error state, a file picker, and a
 * textarea that grows with its content up to the height you allow it.
 */
export default function InputExample() {
  const [note, setNote] = useState('');
  return (
    <div className="grid w-full max-w-md gap-6">
      <Field>
        <FieldLabel htmlFor="input-name">Scheme name</FieldLabel>
        <Input id="input-name" placeholder="Pension scheme 2026" />
      </Field>
      <Field data-disabled>
        <FieldLabel htmlFor="input-code">Scheme code</FieldLabel>
        <Input id="input-code" defaultValue="PS-2026" disabled />
        <FieldDescription>
          Assigned when the scheme is created.
        </FieldDescription>
      </Field>
      <Field data-invalid>
        <FieldLabel htmlFor="input-email">Contact email</FieldLabel>
        <Input
          id="input-email"
          type="email"
          defaultValue="contact@"
          aria-invalid
          aria-describedby="input-email-error"
        />
        <FieldError id="input-email-error">
          Enter a complete email address.
        </FieldError>
      </Field>
      <Field>
        <FieldLabel htmlFor="input-file">Attachment</FieldLabel>
        <Input id="input-file" type="file" />
      </Field>
      <Field>
        <FieldLabel htmlFor="input-note">Note</FieldLabel>
        <Textarea
          id="input-note"
          value={note}
          maxLength={LIMIT}
          className="max-h-40"
          onChange={(event) => setNote(event.target.value)}
          aria-describedby="input-note-count"
        />
        <FieldDescription id="input-note-count">
          {note.length} of {LIMIT} characters
        </FieldDescription>
      </Field>
    </div>
  );
}
```

## Usage

```tsx
import {
  Field,
  FieldLabel,
} from '@workspace/active-ui/components/primitives/field';
import {Input} from '@workspace/active-ui/components/primitives/input';
import {Textarea} from '@workspace/active-ui/components/primitives/textarea';

<Field>
  <FieldLabel htmlFor="name">Name</FieldLabel>
  <Input id="name" autoComplete="name" />
</Field>;

<Textarea id="note" className="max-h-40" />;
```

## States

- **Error:** `aria-invalid` on the control gives it the error border; a `Field` with
  `data-invalid` colours the label and shows the `FieldError`. Point `aria-describedby` at the
  error so that it is read with the field.
- **Disabled:** `disabled` dims the control and removes it from the tab order and from pointer
  input. `data-disabled` on the `Field` dims the label as well.
- **Read-only:** `readOnly` keeps the value selectable and in the tab order, for a value the reader
  may copy but not change.

## Input types

`Input` renders Base UI's `Input`, a native `<input>`: every `type` works. `type="file"` styles the
file button to match. For a number or an amount, use [NumberField](/packages/active-ui/number-field),
which reads the reader's notation; for a password, [`PasswordInput`](/packages/active-ui/password-input).

## Textarea

`Textarea` grows with its content (`field-sizing: content`) from a minimum height of `4rem`. Limit the
growth with a `max-h-*` class: past it, the text scrolls. Browsers without `field-sizing` keep the
minimum height and let the reader resize it.

## What your application provides

- A label for every control: a `FieldLabel` with `htmlFor`, or `aria-label`.
- The value and its validation; the control only shows the state you pass.
- `autoComplete` for personal data (`name`, `email`, `street-address`), so browsers can fill it.

## Accessibility and keyboard

- Native controls: the browser handles typing, selection and the clipboard.
- The focus ring appears on keyboard focus; the error border keeps its colour in focus.
- The font size is `16px` on small screens, so mobile browsers do not zoom in when the field is
  focused.

## API

**Input**

| Prop | Type | Required | Description |
| --- | --- | --- | --- |

Input has no props of its own.

**Textarea**

| Prop | Type | Required | Description |
| --- | --- | --- | --- |

Textarea has no props of its own.

> [!NOTE]
> **Based on shadcn/ui**
>
> This page adapts the Input and Textarea documentation of shadcn/ui (MIT
> licence) to this package; see [Third-party notices](/third-party-notices).
