File Input
A control for selecting, previewing, and removing files to upload.
Installation
Included in poetry-ui — available as
poetry_file_input
the moment you've installed Poetry,
with no per-component step. To own the source and edit it, copy it into your app:
bin/rails g poetry:add file-input
Default
<%= poetry_file_input(name: "document", "aria-label": "Document", class: "w-72") %>
Dropzone
<%= poetry_file_input(variant: :dropzone, name: "attachments[]", multiple: true, hint: "PNG, JPG or PDF, up to 10 MB each", class: "w-full max-w-md") %>
API
Poetry::Ui::FileInput::Component — options are
constructor keywords (the poetry_* helper forwards them);
slots are composed inside the block. Generated from the gem's source documentation.
| Option | Type | Details | Description |
|---|---|---|---|
| variant: | Symbol | one of: input, dropzone; defaults to :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 | defaults to 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 | defaults to false |
Marks the control aria-invalid (set by Field/FormBuilder from model errors). |
| multiple: | Boolean | defaults to 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. |
Styling
Every part carries a stable data-slot attribute — target
[data-slot=…] from your own CSS to restyle it. State rides
data attributes on the parts below. This contract is verified against rendered DOM in CI.
| Part | Description |
|---|---|
| [data-slot=file-input] | The dropzone root - wraps the zone, the selection list, and clear |
| [data-slot=file-input-dropzone] | The <label> drop surface - dashed, platform click-to-browse; its text is the control's accessible name |
| [data-slot=file-input-control] | The native <input type=file> - visually hidden in the dropzone, THE form value in both variants |
| [data-slot=file-input-prompt] | The zone's instruction line (prompt: overrides the default) |
| [data-slot=file-input-hint] | Muted constraints copy under the prompt (hint: - formats, size) |
| [data-slot=file-input-list] | The selected-file <ul> the controller fills (name + size per item; items are controller-built, not server parts) |
| [data-slot=file-input-clear] | The clear affordance - hidden until populated; never re-opens the picker |
State attributes
| Part | Attribute | Condition | Values |
|---|---|---|---|
| file-input | data-variant | always on the dropzone root (the input variant renders the Input component instead) | dropzone |
| file-input | data-dragging | a file drag is over the zone (controller-written, enter/leave counted) | — |
| file-input | data-populated | the native input holds at least one file (controller-written) | — |
Wiring
The Stimulus surface each element carries — declared in the component, verified against rendered DOM in CI. Bare actions fire on the element's default event.
| Element | Controller | Wiring |
|---|---|---|
| root | poetry--core--file-input | registers · value multiple |
| dropzone | poetry--core--file-input | dragenter on dragenter · dragover on dragover · dragleave on dragleave · drop on drop |
| control | poetry--core--file-input | changed on change · target input |
| list | poetry--core--file-input | target list |
| clear | poetry--core--file-input | clear on click · target clear |