# Forms

Input, Textarea, Label and Switch: smooth focus rings, native :user-invalid validation (red only after interaction), aria-invalid, auto-growing textarea with an optional character count, and a spring switch.

- Install all: `npx @kznlabs/labsui add input textarea label switch`
- Page: <https://kznlabs.github.io/labsUI/components/forms>

## Forms (`input`, component)

Input, Textarea, Label and Switch: smooth focus rings, native :user-invalid validation (red only after interaction), aria-invalid, auto-growing textarea with an optional character count, and a spring switch.

- Install: `npx @kznlabs/labsui add input`
- Docs: <https://kznlabs.github.io/labsUI/components/forms>
- Brings: field, label, utils
- npm: clsx@^2.1.1, motion@14.7.1, tailwind-merge@^3.7.0

### API

- `<Input>` (+ <input> props): Works inside <Field> (id and ARIA filled in) and <InputGroup> (chrome handed to the group).

### Usage

```tsx
<Label htmlFor="email">Email</Label><Input id="email" type="email" aria-invalid={err} />
```

### Example: sign-up.tsx

```tsx
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Switch } from "@/components/ui/switch";
import { Textarea } from "@/components/ui/textarea";
export function SignUp({ error }: { error: boolean }) {
  return (
    <form className="grid gap-4">
      <div className="grid gap-2">
        <Label htmlFor="email">Email</Label>
        <Input id="email" type="email" aria-invalid={error} />
      </div>
      <div className="grid gap-2">
        <Label htmlFor="bio">Bio</Label>
        <Textarea id="bio" maxLength={160} />
      </div>
      <Switch defaultChecked />
    </form>
  );
}
```
## Forms (`textarea`, component)

Input, Textarea, Label and Switch: smooth focus rings, native :user-invalid validation (red only after interaction), aria-invalid, auto-growing textarea with an optional character count, and a spring switch.

- Install: `npx @kznlabs/labsui add textarea`
- Docs: <https://kznlabs.github.io/labsUI/components/forms>
- Brings: field, input, label, utils
- npm: clsx@^2.1.1, motion@14.7.1, tailwind-merge@^3.7.0

### API

- `<Textarea>` (+ <textarea> props): Auto-grows with content (`field-sizing: content`); cap with `max-h-*`. Resizable where unsupported (Firefox).
  - `showCount?: boolean`: Show "used / maxLength" in the corner (needs `maxLength`). Turns warning, then red, near the end.

### Usage

```tsx
<Label htmlFor="email">Email</Label><Input id="email" type="email" aria-invalid={err} />
```

### Example: sign-up.tsx

```tsx
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Switch } from "@/components/ui/switch";
import { Textarea } from "@/components/ui/textarea";
export function SignUp({ error }: { error: boolean }) {
  return (
    <form className="grid gap-4">
      <div className="grid gap-2">
        <Label htmlFor="email">Email</Label>
        <Input id="email" type="email" aria-invalid={error} />
      </div>
      <div className="grid gap-2">
        <Label htmlFor="bio">Bio</Label>
        <Textarea id="bio" maxLength={160} />
      </div>
      <Switch defaultChecked />
    </form>
  );
}
```
## Forms (`label`, component)

Input, Textarea, Label and Switch: smooth focus rings, native :user-invalid validation (red only after interaction), aria-invalid, auto-growing textarea with an optional character count, and a spring switch.

- Install: `npx @kznlabs/labsui add label`
- Docs: <https://kznlabs.github.io/labsUI/components/forms>
- Brings: utils
- npm: clsx@^2.1.1, tailwind-merge@^3.7.0

### API

- `<Label>` (+ <label> props)

### Usage

```tsx
<Label htmlFor="email">Email</Label><Input id="email" type="email" aria-invalid={err} />
```

### Example: sign-up.tsx

```tsx
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Switch } from "@/components/ui/switch";
import { Textarea } from "@/components/ui/textarea";
export function SignUp({ error }: { error: boolean }) {
  return (
    <form className="grid gap-4">
      <div className="grid gap-2">
        <Label htmlFor="email">Email</Label>
        <Input id="email" type="email" aria-invalid={error} />
      </div>
      <div className="grid gap-2">
        <Label htmlFor="bio">Bio</Label>
        <Textarea id="bio" maxLength={160} />
      </div>
      <Switch defaultChecked />
    </form>
  );
}
```
## Forms (`switch`, component)

Input, Textarea, Label and Switch: smooth focus rings, native :user-invalid validation (red only after interaction), aria-invalid, auto-growing textarea with an optional character count, and a spring switch.

- Install: `npx @kznlabs/labsui add switch`
- Docs: <https://kznlabs.github.io/labsUI/components/forms>
- Brings: field, label, use-controllable-state, utils
- npm: clsx@^2.1.1, motion@14.7.1, tailwind-merge@^3.7.0

### API

- `<Switch>` (+ <input> props): Native checkbox (role="switch") with a spring knob. Controlled or uncontrolled.
  - `checked?: boolean`: Controlled state; pair with `onCheckedChange`.
  - `defaultChecked?: boolean` = `false`: State at first render (uncontrolled).
  - `onCheckedChange?: (checked: boolean) => void`: Called with the new state.

### Usage

```tsx
<Label htmlFor="email">Email</Label><Input id="email" type="email" aria-invalid={err} />
```

### Example: sign-up.tsx

```tsx
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Switch } from "@/components/ui/switch";
import { Textarea } from "@/components/ui/textarea";
export function SignUp({ error }: { error: boolean }) {
  return (
    <form className="grid gap-4">
      <div className="grid gap-2">
        <Label htmlFor="email">Email</Label>
        <Input id="email" type="email" aria-invalid={error} />
      </div>
      <div className="grid gap-2">
        <Label htmlFor="bio">Bio</Label>
        <Textarea id="bio" maxLength={160} />
      </div>
      <Switch defaultChecked />
    </form>
  );
}
```
