Corex. FileUpload
(Corex v0.1.0-rc.1)
View Source
Phoenix implementation of Zag.js File Upload.
Use multipart on the parent form and read %Plug.Upload{} from params in a controller action, as in Phoenix file uploads.
LiveView phx-submit cannot transport raw multipart file bytes over the WebSocket; use a controller route for classic Plug.Upload, or allow_upload/3 for LiveView-native uploads with Corex.FileUploadLive (<.file_upload_live>). Do not combine this Zag component with live_file_input on the same file control.
Anatomy
Minimal
<.file_upload name="document" class="file-upload">
<:close>
<.heroicon name="hero-x-mark" />
</:close>
</.file_upload>With label
<.file_upload name="document" class="file-upload">
<:label>Files</:label>
<:close>
<.heroicon name="hero-x-mark" />
</:close>
</.file_upload>Custom slots
<.file_upload name="document" class="file-upload">
<:dropzone>
<span>Custom dropzone</span>
</:dropzone>
<:open>
<span>Custom trigger</span>
</:open>
<:close>
<.heroicon name="hero-x-mark" />
</:close>
</.file_upload>Multipart form (controller)
<.form for={@form} action={~p"/file-upload/form"} method="post" multipart>
<input type="hidden" name="file_upload_changeset[_sent]" value="1" />
<.file_upload field={@form[:attachment]} class="file-upload">
<:label>Attachment</:label>
<:close>
<.heroicon name="hero-x-mark" />
</:close>
<:error :let={msg}>
<.heroicon name="hero-exclamation-circle" class="icon" />
{msg}
</:error>
</.file_upload>
<.action type="submit" class="button button--accent w-full">Submit</.action>
</.form>Use multipart on the parent form so %Plug.Upload{} is available on the server for classic uploads. Optional hidden _sent supports used_input? when validating empty submits.
API
Requires a stable id on <.file_upload>.
| Function | Action | Returns |
|---|---|---|
clear_files/1 | Clear accepted files (client) | %Phoenix.LiveView.JS{} |
clear_files/2 | Clear accepted files (server) | socket |
clear_rejected_files/1 | Clear rejected list (client) | %Phoenix.LiveView.JS{} |
clear_rejected_files/2 | Clear rejected list (server) | socket |
open_file_picker/1 | Open native picker (client) | %Phoenix.LiveView.JS{} |
open_file_picker/2 | Open native picker (server) | socket |
Events
Pick an event name and pass it to on_* on <.file_upload>. Rejected files are not listed in the DOM; use on_file_reject to react to validation failures.
Server events
| Event | When | Payload |
|---|---|---|
on_file_change="files_changed" | Accepted file list changes | %{"id" => id, ...} |
on_file_accept="file_accepted" | File passes validation | %{"id" => id, ...} |
on_file_reject="file_rejected" | File fails validation | %{"id" => id, ...} |
Client events
| Event | When | event.detail |
|---|---|---|
on_file_change_client="files-changed" | Accepted list changes | id, file metadata |
on_file_accept_client="file-accepted" | File accepted | id, file metadata |
on_file_reject_client="file-rejected" | File rejected | id, reason |
Form
See Multipart form under Anatomy. Use field={f[:attachment]} inside <.form multipart>.
For cross-cutting invalid styling and error presentation, see the Forms guide.
Summary
API
Drop every accepted file entry from phx-click. Dispatches corex:file-upload:clear-files.
Clear accepted files from handle_event (file_upload_clear_files).
Remove rejected entries from phx-click. Dispatches corex:file-upload:clear-rejected.
Clear rejected files from handle_event (file_upload_clear_rejected).
Open the OS file picker from phx-click. Dispatches corex:file-upload:open.
Open the OS file picker from handle_event (file_upload_open).
Components
Attributes
id(:string) - Stable id for the file upload root; set automatically when using field.disabled(:boolean) - Whether the file upload is disabled. Defaults tofalse.invalid(:boolean) - Whether the file upload is invalid. Defaults tofalse.read_only(:boolean) - Whether the file upload is read-only. Defaults tofalse.required(:boolean) - Whether at least one file is required. Defaults tofalse.name(:string) - The name attribute of the hidden file input.form(:string) - The id of the form this control belongs to.dir(:string) - Text direction (ltr or rtl). Defaults tonil. Must be one ofnil,"ltr", or"rtl".max_files(:integer) - Maximum number of files the user may select. Defaults to1.max_file_size(:integer) - Maximum file size in bytes; omit for no limit. Defaults tonil.min_file_size(:integer) - Minimum file size in bytes; omit for no limit. Defaults tonil.allow_drop(:boolean) - Whether drag-and-drop onto the dropzone is enabled. Defaults totrue.prevent_document_drop(:boolean) - When true, prevents dropping files on the document outside the dropzone. Defaults totrue.accept(:string) - Comma-separated MIME types or extensions (e.g. image/*,.pdf). Defaults tonil.directory(:boolean) - When true, allow selecting a directory instead of individual files. Defaults tofalse.on_file_change(:string) - Server event when the accepted file list changes. Defaults tonil.on_file_change_client(:string) - Client event name when the accepted file list changes. Defaults tonil.on_file_accept(:string) - Server event when a file passes validation. Defaults tonil.on_file_accept_client(:string) - Client event name when a file passes validation. Defaults tonil.on_file_reject(:string) - Server event when a file fails validation. Defaults tonil.on_file_reject_client(:string) - Client event name when a file fails validation. Defaults tonil.translation(Corex.FileUpload.Translation) - Override translatable strings. Defaults tonil.errors(:list) - List of error messages when not using field=. Defaults to[].field(Phoenix.HTML.FormField) - Form field for id, name, form, invalid, and required wiring.- Global attributes are accepted.
Slots
label- Label above the dropzone. Accepts attributes:class(:string)
dropzone- Custom dropzone content; defaults to translation dropzone text.open- Custom open-picker trigger; defaults to translation open text.close(required) - Remove control for each accepted file entry. Accepts attributes:class(:string)
error- Error message content; receives the message as slot argument. Accepts attributes:class(:string)
API
Drop every accepted file entry from phx-click. Dispatches corex:file-upload:clear-files.
<.action phx-click={Corex.FileUpload.clear_files("my-fu")}>Clear accepted</.action>
<.file_upload id="my-fu" class="file-upload" accept="image/*">
<:close><.heroicon name="hero-x-mark" /></:close>
</.file_upload>document.getElementById("my-fu")?.dispatchEvent(new CustomEvent("corex:file-upload:clear-files", { bubbles: false }));
Clear accepted files from handle_event (file_upload_clear_files).
def handle_event("clear_files", _, socket) do
{:noreply, Corex.FileUpload.clear_files(socket, "my-fu")}
end
Remove rejected entries from phx-click. Dispatches corex:file-upload:clear-rejected.
<.action phx-click={Corex.FileUpload.clear_rejected_files("my-fu")}>Clear rejected</.action>
<.file_upload id="my-fu" class="file-upload">
<:close><.heroicon name="hero-x-mark" /></:close>
</.file_upload>
Clear rejected files from handle_event (file_upload_clear_rejected).
def handle_event("clear_rejected", _, socket) do
{:noreply, Corex.FileUpload.clear_rejected_files(socket, "my-fu")}
end
Open the OS file picker from phx-click. Dispatches corex:file-upload:open.
<.action phx-click={Corex.FileUpload.open_file_picker("my-fu")}>Browse</.action>
<.file_upload id="my-fu" class="file-upload">
<:close><.heroicon name="hero-x-mark" /></:close>
</.file_upload>
Open the OS file picker from handle_event (file_upload_open).
def handle_event("browse", _, socket) do
{:noreply, Corex.FileUpload.open_file_picker(socket, "my-fu")}
end