# Input

> Text input field component for forms with consistent styling and accessibility

## Installation

```bash
pnpm add @wandercom/design-system-web
```

## Usage

```tsx
import { Input } from '@wandercom/design-system-web/ui/input';

export function Example() {
  return <Input type="email" placeholder="Email" />;
}
```

## Examples

```tsx
import { Input } from "@wandercom/design-system-web/ui/input";

export function InputVariants() {
  return (
    <div className="flex max-w-sm flex-col gap-8">
      <div className="flex flex-col gap-2">
        <label className="text-body text-secondary" htmlFor="default-size">
          Default size
        </label>
        <Input id="default-size" placeholder="Enter your name" type="text" />
      </div>
      <div className="flex flex-col gap-2">
        <label className="text-body text-secondary" htmlFor="small-size">
          Small size
        </label>
        <Input
          id="small-size"
          placeholder="Enter your name"
          size="sm"
          type="text"
        />
      </div>
      <div className="flex flex-col gap-2">
        <label className="text-body text-secondary" htmlFor="disabled">
          Disabled
        </label>
        <Input id="disabled" placeholder="Enter your name" type="text" />
      </div>
      <div className="flex flex-col gap-2">
        <label className="text-body text-secondary" htmlFor="invalid">
          Invalid
        </label>
        <Input
          aria-invalid="true"
          defaultValue="Invalid value"
          id="invalid"
          placeholder="Invalid input"
          type="text"
        />
      </div>
    </div>
  );
}

```

### Character count

Compose `Input` (via `InputGroupInput`) with the `useCharacterLimit` hook and `InputGroupCharacterCount` addon to display a live `count/max` counter. Any input — typing, paste, drop, IME — that would push the value past `maxLength` is rejected; the value can never exceed the cap. Plug your form library (React Hook Form, TanStack Form, Zod, etc.) into `onValueChange` to sync state.

```tsx
"use client";

import {
  InputGroup,
  InputGroupAddon,
  InputGroupCharacterCount,
  InputGroupInput,
  useCharacterLimit,
} from "@wandercom/design-system-web/ui/input-group";

const MAX_LENGTH = 40;

export function InputGroupCharacterCountExample() {
  const large = useCharacterLimit({
    maxLength: MAX_LENGTH,
    defaultValue: "Coastal cottage in Mendocino",
  });
  const small = useCharacterLimit({
    maxLength: MAX_LENGTH,
    defaultValue: "Coastal cottage in Mendocino",
  });

  return (
    <div className="flex w-full max-w-sm flex-col gap-4">
      <div className="flex flex-col gap-2">
        <span className="text-body text-secondary">Default</span>
        <InputGroup>
          <InputGroupInput {...large.inputProps} placeholder="Listing title" />
          <InputGroupAddon align="inline-end">
            <InputGroupCharacterCount
              count={large.count}
              maxLength={large.maxLength}
            />
          </InputGroupAddon>
        </InputGroup>
      </div>
      <div className="flex flex-col gap-2">
        <span className="text-body text-secondary">Small</span>
        <InputGroup size="sm">
          <InputGroupInput {...small.inputProps} placeholder="Listing title" />
          <InputGroupAddon align="inline-end">
            <InputGroupCharacterCount
              count={small.count}
              maxLength={small.maxLength}
            />
          </InputGroupAddon>
        </InputGroup>
      </div>
    </div>
  );
}

```

```tsx
import {
  InputGroup,
  InputGroupAddon,
  InputGroupCharacterCount,
  InputGroupInput,
  useCharacterLimit,
} from '@wandercom/design-system-web/ui/input-group';

export function Example() {
  const { count, maxLength, inputProps } = useCharacterLimit({
    maxLength: 40,
  });

  return (
    <InputGroup>
      <InputGroupInput {...inputProps} placeholder="Listing title" />
      <InputGroupAddon align="inline-end">
        <InputGroupCharacterCount count={count} maxLength={maxLength} />
      </InputGroupAddon>
    </InputGroup>
  );
}
```

## Props

| Prop | Type | Description |
| --- | --- | --- |
| size?: | `'default' | 'sm'` | Size variant of the input. Defaults to default. |
| type?: | `string` | HTML input type (text, email, password, file, etc.). Defaults to text. |
| placeholder?: | `string` | Placeholder text displayed when input is empty. |
| disabled?: | `boolean` | Disables the input field when true. |
| className?: | `string` | Additional CSS classes to apply. |
| ref?: | `React.Ref<HTMLInputElement>` | Forward ref to the underlying input element. |