PhiaUi.Components.FileUpload (phia_ui v0.1.17)

Copy Markdown View Source

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
   )}
end

Then 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 &amp; 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)}
end

Consuming 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

file_upload(assigns)

Renders a drag-and-drop file upload zone for any file type.

Renders:

  1. A <label> / hidden <input type="file"> pair as the clickable trigger.
  2. A styled drop zone with phx-drop-target bound when upload.ref is present.
  3. An optional file list when upload.entries is non-empty, rendered via the :file slot.

Attributes

  • upload (:any) - A Phoenix.LiveView.UploadConfig struct returned by @uploads.field_name, or a plain map with :ref and :entries keys. When nil, only the drop zone and :empty slot 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 to nil.

  • class (:string) - Additional CSS classes applied to the outer wrapper div. Defaults to nil.

Slots

  • empty - Content rendered inside the drop zone when no entries are present (or upload is nil).
  • file - Content rendered for each entry in upload.entries. Receives each entry as its :let value. Use <.file_upload_entry entry={entry} on_cancel="cancel_upload" /> inside this slot for the default row rendering.

file_upload_entry(assigns)

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)}
end

Attributes

  • entry (:any) (required) - A Phoenix.LiveView.UploadEntry struct or a plain map with at least: :client_name, :progress (0–100), :ref, and :errors keys.

  • 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 to nil.