File upload component for PhiaUI.
Provides file_upload/1 — a drag-and-drop file upload zone for any file type,
and file_upload_entry/1 — a file row with progress bar, error messages, and
a cancel button.
Unlike image_upload/1 which is purpose-built for image previews,
file_upload/1 handles any file type, renders a prominent drop zone,
and exposes slots for full customization of the entry list.
Requirements
The parent LiveView must configure the upload with allow_upload/3 in mount/3:
def mount(_params, _session, socket) do
{:ok,
socket
|> allow_upload(:documents,
accept: ~w(.pdf .docx .xlsx),
max_entries: 5,
max_file_size: 10_485_760 # 10 MB
)}
endThen pass @uploads.documents as the :upload attribute.
Basic example
<.form for={@form} phx-submit="save" phx-change="validate">
<.file_upload upload={@uploads.documents} label="Upload Documents" accept=".pdf,.docx">
<:empty>
<p>Drag & drop files here or click to browse</p>
</:empty>
<:file :let={entry}>
<.file_upload_entry entry={entry} on_cancel="cancel_upload" />
</:file>
</.file_upload>
<.button type="submit">Save</.button>
</.form>Handling entry cancellation
Add this event handler to support the cancel (×) button:
def handle_event("cancel_upload", %{"ref" => ref}, socket) do
{:noreply, cancel_upload(socket, :documents, ref)}
endConsuming uploads after form submission
def handle_event("save", _params, socket) do
urls =
consume_uploaded_entries(socket, :documents, fn %{path: tmp_path}, _entry ->
dest = Path.join([:code.priv_dir(:my_app), "static", "uploads",
Path.basename(tmp_path)])
File.cp!(tmp_path, dest)
{:ok, "/uploads/" <> Path.basename(dest)}
end)
{:noreply, assign(socket, uploaded_files: urls)}
end
Summary
Functions
Renders a drag-and-drop file upload zone for any file type.
Renders a single file entry row with filename, progress bar, error messages, and a cancel button.
Functions
Renders a drag-and-drop file upload zone for any file type.
Renders:
- A
<label>/ hidden<input type="file">pair as the clickable trigger. - A styled drop zone with
phx-drop-targetbound whenupload.refis present. - An optional file list when
upload.entriesis non-empty, rendered via the:fileslot.
Attributes
upload(:any) - APhoenix.LiveView.UploadConfigstruct returned by@uploads.field_name, or a plain map with:refand:entrieskeys. When nil, only the drop zone and:emptyslot are rendered.Defaults to
nil.label(:string) - Label text rendered inside the<label>element above the drop zone. Defaults to"Upload Files".accept(:string) - File type filter forwarded to the<input type="file" accept=...>attribute. Defaults tonil.class(:string) - Additional CSS classes applied to the outer wrapper div. Defaults tonil.
Slots
empty- Content rendered inside the drop zone when no entries are present (or upload is nil).file- Content rendered for each entry inupload.entries. Receives each entry as its:letvalue. Use<.file_upload_entry entry={entry} on_cancel="cancel_upload" />inside this slot for the default row rendering.
Renders a single file entry row with filename, progress bar, error messages, and a cancel button.
The cancel button emits phx-click={@on_cancel} with phx-value-ref set to
the entry's :ref. The LiveView must handle this event:
def handle_event("cancel_upload", %{"ref" => ref}, socket) do
{:noreply, cancel_upload(socket, :documents, ref)}
endAttributes
entry(:any) (required) - APhoenix.LiveView.UploadEntrystruct or a plain map with at least::client_name,:progress(0–100),:ref, and:errorskeys.on_cancel(:string) - The LiveView event name fired when the cancel button is clicked. Defaults to"cancel_upload".class(:string) - Additional CSS classes applied to the entry row div. Defaults tonil.