File upload
NewOverview
A LiveView file upload dropzone with progress, validation errors, previews, and removal controls.
FileUpload styles the native LiveView
file input
and renders the entries in its UploadConfig. LiveView owns selection,
drag and drop, validation, progress, temporary storage, and external uploads.
Call allow_upload/3
in the parent LiveView, place the component inside a form with phx-change,
handle cancel-upload, and consume completed entries. This example uses
auto_upload: true
with a progress callback, so it does not need a submit
button. Uploads that wait for form submission can consume entries in phx-submit
instead. The same component works with
LiveViewβs default temporary files, external uploads, or a custom streaming writer.
Read the LiveView upload guide
for setup, validation, and storage options. For an example that streams entries through a
custom writer, see Streaming uploads with LiveView.
@impl Phoenix.LiveView
def mount(_params, _session, socket) do
{:ok,
allow_upload(socket, :project_files,
accept: ~w(.jpg .jpeg .png),
max_entries: 3,
max_file_size: 5_000_000,
progress: &handle_progress/3,
auto_upload: true
)}
end
@impl Phoenix.LiveView
def handle_event("validate-file-upload", _params, socket), do: {:noreply, socket}
def handle_event("cancel-upload", %{"ref" => ref}, socket) do
{:noreply, cancel_upload(socket, :project_files, ref)}
end
defp handle_progress(:project_files, entry, socket) do
if entry.done? do
uploaded_file =
consume_uploaded_entry(socket, entry, fn %{path: path} ->
destination = Path.join(["priv", "static", "uploads", entry.uuid <> Path.extname(entry.client_name)])
File.cp!(path, destination)
{:ok, destination}
end)
{:noreply, update(socket, :uploaded_files, &(&1 ++ [uploaded_file]))}
else
{:noreply, socket}
end
end
The preview slot receives each UploadEntry. This example uses
live_img_preview/1
and automatically consumes completed uploads; omit the slot to show the default file icon.
<Form.form
for={@form}
id="project-files-form"
phx-change="validate-file-upload"
class="mx-auto w-full max-w-lg"
>
<FileUpload.file_upload
upload={@uploads.project_files}
label="Project images"
sublabel="(optional)"
>
<:preview :let={entry}>
<.live_img_preview entry={entry} alt="" />
</:preview>
</FileUpload.file_upload>
</Form.form>
Auto Upload
Set auto_upload: true
to start uploading files when they are selected.
Otherwise, LiveView waits until the form is submitted. The example below uses
auto_upload: false
and includes a submit button. See
allow_upload/3
for the remaining upload options.
<Form.form
for={@form}
id="manual-project-files-form"
phx-change="validate-file-upload"
phx-submit="save-manual-upload"
class="mx-auto w-full max-w-lg"
>
<FileUpload.file_upload
upload={@uploads.manual_project_files}
label="Project images"
cancel_event="cancel-manual-upload"
>
<:preview :let={entry}>
<.live_img_preview entry={entry} alt="" />
</:preview>
</FileUpload.file_upload>
<div class="flex justify-end">
<Button.button type="submit">Upload images</Button.button>
</div>
</Form.form>
Validation and Errors
Upload constraints are configured with allow_upload/3. The error slot
receives each validation reason so applications can replace the default messages. This
example accepts up to two PNG files no larger than 100 KB each.
<Form.form
for={@form}
id="validation-files-form"
phx-change="validate-file-upload"
class="mx-auto w-full max-w-lg"
>
<FileUpload.file_upload
upload={@uploads.validation_files}
label="PNG files"
cancel_event="cancel-validation-upload"
>
<:error :let={reason}>
{case reason do
:too_many_files -> "Choose no more than two files."
:too_large -> "Choose a PNG file smaller than 100 KB."
:not_accepted -> "Choose a PNG file."
_ -> "The file could not be uploaded."
end}
</:error>
</FileUpload.file_upload>
</Form.form>
Document Upload
Omit the preview slot for non-image uploads to use the default file icon. This example accepts PDF files and waits for the form to be submitted before uploading them.
<Form.form
for={@form}
id="document-files-form"
phx-change="validate-file-upload"
phx-submit="save-document-upload"
class="mx-auto w-full max-w-lg"
>
<FileUpload.file_upload
upload={@uploads.document_files}
label="Documents"
cancel_event="cancel-document-upload"
/>
<div class="flex justify-end">
<Button.button type="submit">Upload documents</Button.button>
</div>
</Form.form>
Accessibility
The file_upload
component uses an
input of type file
under the hood, so the bulk of the accessibility needs are met there.
Add this module
mix dizzy.add file_upload
Component API
FileUpload.file_upload
Attributes
| Name | Type | Default | Values |
|---|---|---|---|
cancel_event |
:string
| "cancel-upload" | β |
cancel_target |
:any
| nil | β |
class |
:any
| nil | β |
description |
:string
| nil | β |
disabled |
:boolean
| false | β |
id |
:string
| nil | β |
label |
:string
| Required | β |
required |
:boolean
| false | β |
rest |
:global
| nil | β |
sublabel |
:string
| nil | β |
upload |
{:struct, Phoenix.LiveView.UploadConfig}
| Required | β |
Slots
| Name | Required |
|---|---|
error | Optional |
preview | Optional |