

# FileInput

File picker dropzone with click-to-browse, drag-and-drop, and client-side `accept` / `maxSize` / `maxFiles` validation. Always controlled via `value` and `onChange`.

## Examples

### Default

Pass a required `label`, controlled `value` / `onChange`, and optional `accept` filters.

```tsx
import { FileInput } from '@var-ui/react';

<FileInput label="Upload" value={file} onChange={setFile} accept=".pdf,image/*" />
```

```astro
<!-- No Astro binding yet — use @var-ui/react -->
```

```html
<!-- No HTML demo yet — use @var-ui/react -->
```

### Multiple files

Set `multiple` so `value` is a `File[]` (or `null` when cleared). Optionally cap the count with `maxFiles`.

```tsx
import { FileInput } from '@var-ui/react';
import { useState } from 'react';

const [files, setFiles] = useState<File[] | null>(null);

<FileInput
  label="Attachments"
  value={files}
  onChange={setFiles}
  multiple
  accept="image/*,.pdf"
/>
```

```astro
<!-- No Astro binding yet — use @var-ui/react -->
```

```html
<!-- No HTML demo yet — use @var-ui/react -->
```

## Props

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| label | string | yes |  | Visible label rendered above the dropzone. |
| onChange | (files: File \| File[] \| null) => void | yes |  | Called with the new selection, or `null` when cleared. |
| value | File \| File[] \| null | yes |  | Selected file(s); `File[]` when `multiple`, otherwise a single `File` or `null`. |
| accept | string \| undefined | no |  | Comma-separated list of accepted `.ext`, `type/*`, or exact mime types (matches the HTML `accept` attribute). |
| className | string \| undefined | no |  | Additional CSS class names merged onto the root element. |
| description | string \| undefined | no |  | Helper text shown below the control when there is no error. |
| errorMessage | string \| undefined | no |  | Validation message; when set, takes precedence over internally-derived validation errors. |
| isDisabled | boolean \| undefined | no |  | Disables the dropzone: blocks click, keyboard activation, and drop. |
| maxFiles | number \| undefined | no |  | Maximum number of files accepted when `multiple`. Extra files are rejected. |
| maxSize | number \| undefined | no |  | Maximum size per file, in bytes. Oversized files are rejected. |
| multiple | boolean \| undefined | no |  | Allow selecting/dropping more than one file. |

## Accessibility

The dropzone is a focusable `role="button"` activated with Enter/Space, labelled by the visible field label and described by `description` / error text. The native file input is visually hidden (`aria-hidden`) and opened programmatically. The clear control has an explicit `aria-label` (“Clear …”).
