LiveVue 1.0
Examples File Upload

File Upload

Upload files with useLiveUpload() powered by Phoenix LiveView's built-in upload handling. Includes drag-and-drop, progress tracking, and server-side processing.

What this example shows

1
useLiveUpload()
Upload state and progress
2
allow_upload/3
Server-side config
3
Drag & Drop
addFiles() helper
file_upload_live.ex
defmodule MyAppWeb.FileUploadLive do
  use MyAppWeb, :live_view

  def render(assigns) do
    ~H"""
    <.vue
      upload={@uploads.document}
      uploadedFile={@uploaded_file}
      v-component="FileUpload"
      v-socket={@socket}
    />
    """
  end

  def mount(_params, _session, socket) do
    {:ok,
     socket
     |> assign(:uploaded_file, nil)
     |> allow_upload(:document,
       accept: ~w(.pdf .txt .png .jpg .jpeg),
       max_entries: 1,
       max_file_size: 5_000_000,
       auto_upload: true
     )}
  end

  def handle_event("validate", _params, socket) do
    {:noreply, socket}
  end

  def handle_event("cancel-upload", %{"ref" => ref}, socket) do
    {:noreply, cancel_upload(socket, :document, ref)}
  end

  def handle_event("save", _params, socket) do
    [file_stats] =
      consume_uploaded_entries(socket, :document, fn %{path: _path}, entry ->
        {:ok,
         %{
           name: entry.client_name,
           size: entry.client_size,
           type: entry.client_type
         }}
      end)

    {:noreply, assign(socket, :uploaded_file, file_stats)}
  end

  def handle_event("reset", _params, socket) do
    {:noreply, assign(socket, :uploaded_file, nil)}
  end
end

How it works

1 Configure uploads with allow_upload/3

In the LiveView mount, use allow_upload/3 to configure accepted file types, limits, and auto-upload behavior.

allow_upload(:document,
  accept: ~w(.pdf .txt .png .jpg .jpeg),
  max_entries: 1,
  max_file_size: 5_000_000,
  auto_upload: true
)

2 Initialize with useLiveUpload()

Pass the upload config from props and specify event names. The hook returns reactive state and helper functions.

const {
  entries,
  showFilePicker,
  addFiles,
  progress,
  cancel,
  valid
} = useLiveUpload(() => props.upload, {
  changeEvent: "validate",
  submitEvent: "save"
})

3 Handle drag and drop

Use addFiles() with the DataTransfer object from drop events.

<div
  @drop.prevent="addFiles($event.dataTransfer)"
  @dragover.prevent
  @click="showFilePicker"
>
  <!-- Drop zone content -->
</div>

4 Track upload progress

Each entry in entries has progress (0-100), client_name, client_size, and errors.

<div v-for="entry in entries" :key="entry.ref">
  {{ entry.client_name }} - {{ entry.progress }}%
  <button @click="cancel(entry.ref)">Cancel</button>
</div>

5 Process uploads on the server

Use consume_uploaded_entries/3 to process files. The callback receives the temporary file path and entry metadata.

consume_uploaded_entries(socket, :document, fn %{path: path}, entry ->
  # Process file: copy, analyze, store, etc.
  {:ok, %{name: entry.client_name, size: entry.client_size}}
end)
Next up: Phoenix Streams for efficient list updates
View example