## file_input (`poetry_file_input`)

A control for selecting, previewing, and removing files to upload.

Class: Poetry::Ui::FileInput::Component - BEM block `poetry-ui-file_input`.
- `variant:` (symbol) - one of input|dropzone, default "input" - :input is the compact native control; :dropzone the drag-and-drop surface.
- `accept:` (string) - The native accept filter (e.g. "image/*,.pdf").
- `described_by:` (string) - Ids for the native input's aria-describedby (Field wires this).
- `disabled:` (boolean) - default false - Disables the native input and dims the dropzone.
- `hint:` (string) - Muted constraints copy under the prompt (formats, size limits).
- `id:` (string) - The native input's id (Field/FormBuilder wire it to the label).
- `invalid:` (boolean) - default false - Marks the control aria-invalid (set by Field/FormBuilder from model errors).
- `multiple:` (boolean) - default false - Allows selecting several files; forwarded to the native input.
- `name:` (string) - The native input's name - the submitted param (multiple: true wants a name ending in [] for Rails params).
- `prompt:` (string) - The dropzone's instruction line - overrides the translated default.
- PART `file-input` - The dropzone root - wraps the zone, the selection list, and clear | states: data-variant=dropzone (always on the dropzone root (the input variant renders the Input component instead)); data-dragging (a file drag is over the zone (controller-written, enter/leave counted)); data-populated (the native input holds at least one file (controller-written))
- PART `file-input-dropzone` - The <label> drop surface - dashed, platform click-to-browse; its text is the control's accessible name
- PART `file-input-control` - The native <input type=file> - visually hidden in the dropzone, THE form value in both variants
- PART `file-input-prompt` - The zone's instruction line (prompt: overrides the default)
- PART `file-input-hint` - Muted constraints copy under the prompt (hint: - formats, size)
- PART `file-input-list` - The selected-file <ul> the controller fills (name + size per item; items are controller-built, not server parts)
- PART `file-input-clear` - The clear affordance - hidden until populated; never re-opens the picker
- WIRING root: `poetry--core--file-input` registers; values multiple
- WIRING dropzone: `poetry--core--file-input` actions dragenter on dragenter, dragover on dragover, dragleave on dragleave, drop on drop
- WIRING control: `poetry--core--file-input` actions changed on change; targets input
- WIRING list: `poetry--core--file-input` targets list
- WIRING clear: `poetry--core--file-input` actions clear on click; targets clear
- RULE: File selection is a FileInput: variant: :input for compact forms, :dropzone when dragging is expected (uploads as the page's point) - never a hand-rolled drop div.
- RULE: The native input is the form value: set name: (multiple: true wants a name ending in [] for Rails params); ActiveStorage direct upload attaches to it as usual.
- RULE: The dropzone's selected-file list and clear button are controller-rendered - compose prompt:/hint: copy instead of adding your own list markup.
- RULE: In a Field, prefer form.file_input (the builder wires id/label/errors); the bare component suits standalone dropzones.
