# Input (Caseroom component)

A text field with a 3:1 border and an invalid state. Black and white, dark mode, shadcn-compatible; React, Astro and plain HTML.

39% of the 2,062 sites in The UI Index have a form (806 sites).

## Install

- React: `npx shadcn@latest add https://www.themes.dev/caseroom/r/input.json`
- Astro: `npx shadcn@latest add https://www.themes.dev/caseroom/r/astro/input.json`
- HTML: https://www.themes.dev/caseroom/r/html/input.html (with https://www.themes.dev/caseroom/r/html/caseroom.css)

Page: https://www.themes.dev/caseroom/components/input/ · Rules for agents: https://www.themes.dev/caseroom/AGENT.md

## Code

### input.astro

```astro
---
import type { HTMLAttributes } from 'astro/types';
import { cn } from '@/lib/utils';
import { inputClasses } from './input.variants';

type Props = HTMLAttributes<'input'>;
const { class: className, type = 'text', ...rest } = Astro.props;
---

<input type={type} class={cn(inputClasses, className)} {...rest} />
```

### input.tsx

```tsx
import type { InputHTMLAttributes } from 'react';
import { cn } from '@/lib/utils';
import { inputClasses } from './input.variants';

export type InputProps = InputHTMLAttributes<HTMLInputElement>;

/** A text field. Always pair it with a <Label htmlFor>; set aria-invalid and aria-describedby for errors. */
export function Input({ className, type = 'text', ...props }: InputProps) {
  return <input type={type} className={cn(inputClasses, className)} {...props} />;
}
```

### input.variants.ts

```tsx
/** Shared by input and textarea. The border has 3:1 contrast (WCAG 1.4.11); aria-invalid turns it destructive. */
export const fieldClasses =
  'w-full min-w-0 rounded-md border border-input bg-background px-3 text-sm text-foreground transition-colors placeholder:text-muted-foreground enabled:hover:border-foreground/85 enabled:active:bg-muted aria-invalid:enabled:hover:border-destructive aria-invalid:enabled:hover:bg-[color-mix(in_oklab,var(--destructive)_6%,var(--background))] aria-invalid:enabled:active:bg-[color-mix(in_oklab,var(--destructive)_10%,var(--background))] focus-visible:border-ring focus-visible:outline-2 focus-visible:outline-offset-0 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:outline-destructive';

export const inputClasses = `${fieldClasses} h-9 py-1 file:mr-3 file:border-0 file:bg-transparent file:text-sm file:font-medium`;
```
