Fluxon (Fluxon v3.1.1)
To use Fluxon components in your LiveView or View modules, add the following to your module:
use FluxonThis will import all available components. You can customize which components to import using the following options:
:only- List of components to import. Only the specified components will be imported.use Fluxon, only: [:button, :input, :modal]:except- List of components to exclude. All components except the specified ones will be imported.use Fluxon, except: [:table, :tabs]
Summary
Functions
Removes any flash-queued toasts that have not yet been delivered to the client.
Closes a autocomplete component by id. Same call shapes as open_autocomplete/1.
Closes a date picker component by id. Same call shapes as open_date_picker/1.
Closes a dialog component by id. Same call shapes as open_dialog/1.
Closes a dropdown component by id. Same call shapes as open_dropdown/1.
Closes a popover component by id. Same call shapes as open_popover/1.
Closes a select component by id. Same call shapes as open_select/1.
Closes a tags input component by id. Same call shapes as open_tags_input/1.
Closes a tooltip component by id. Same call shapes as open_tooltip/1.
Programmatically dismisses a toast by id.
Opens a autocomplete component by id.
Opens a autocomplete component from a server handler (Socket) or by chaining
onto an existing Phoenix.LiveView.JS pipeline.
Opens a date picker component by id.
Opens a date picker component from a server handler (Socket) or by chaining
onto an existing Phoenix.LiveView.JS pipeline.
Opens a dialog component by id.
Opens a dialog component from a server handler (Socket) or by chaining
onto an existing Phoenix.LiveView.JS pipeline.
Opens a dropdown component by id.
Opens a dropdown component from a server handler (Socket) or by chaining
onto an existing Phoenix.LiveView.JS pipeline.
Opens a popover component by id.
Opens a popover component from a server handler (Socket) or by chaining
onto an existing Phoenix.LiveView.JS pipeline.
Opens a select component by id.
Opens a select component from a server handler (Socket) or by chaining
onto an existing Phoenix.LiveView.JS pipeline.
Opens a tags input component by id.
Opens a tags input component from a server handler (Socket) or by chaining
onto an existing Phoenix.LiveView.JS pipeline.
Opens a tooltip component by id.
Opens a tooltip component from a server handler (Socket) or by chaining
onto an existing Phoenix.LiveView.JS pipeline.
Queues a toast notification that survives navigation.
Resolves a previously-shown toast (typically a loading toast) with a new title and, optionally, a new color.
Shows a rich, in-LiveView toast.
Shows an indeterminate loading toast, designed to be resolved later via
resolve_toast/4.
Toggles a autocomplete component by id. Same call shapes as open_autocomplete/1.
Toggles a date picker component by id. Same call shapes as open_date_picker/1.
Toggles a dialog component by id. Same call shapes as open_dialog/1.
Toggles a dropdown component by id. Same call shapes as open_dropdown/1.
Toggles a popover component by id. Same call shapes as open_popover/1.
Toggles a select component by id. Same call shapes as open_select/1.
Toggles a tags input component by id. Same call shapes as open_tags_input/1.
Toggles a tooltip component by id. Same call shapes as open_tooltip/1.
Functions
Removes any flash-queued toasts that have not yet been delivered to the client.
Useful in long-lived LiveViews where toasts have accumulated under the
Fluxon flash key but no navigation has flushed them. After this call,
pending flash toasts are wiped - already-visible toasts are unaffected;
use dismiss_toast/2 for those.
Accepts both Phoenix.LiveView.Socket and Plug.Conn.
Closes a autocomplete component by id. Same call shapes as open_autocomplete/1.
Closes a date picker component by id. Same call shapes as open_date_picker/1.
Closes a dialog component by id. Same call shapes as open_dialog/1.
Closes a dropdown component by id. Same call shapes as open_dropdown/1.
Closes a popover component by id. Same call shapes as open_popover/1.
Closes a select component by id. Same call shapes as open_select/1.
Closes a tags input component by id. Same call shapes as open_tags_input/1.
Closes a tooltip component by id. Same call shapes as open_tooltip/1.
Programmatically dismisses a toast by id.
Has three forms, mirroring send_toast/3:
dismiss_toast(socket, id)- pushes a channel event from a handler.dismiss_toast(id)- returns a%JS{}for use inphx-click={...}.dismiss_toast(%JS{}, id)- chains onto an existing JS pipeline.
Works for both flash-queued (put_toast/3) and live (send_toast/3)
toasts - once shown, every toast is identified the same way on the
client. Calling this for an unknown id is a no-op.
Examples
# From a server handler
def handle_info({:upload_done, id}, socket) do
{:noreply, Fluxon.dismiss_toast(socket, id)}
end
# From a phx-click, no server round-trip
<.button phx-click={Fluxon.dismiss_toast("upload-progress")}>
Cancel
</.button>
Opens a autocomplete component by id.
Returns a Phoenix.LiveView.JS struct that dispatches a DOM event to the
target element. The id may be passed as "my-id" or "#my-id"; both
forms resolve to the same target.
Examples
<.button phx-click={Fluxon.open_autocomplete("my-autocomplete")}>Open</.button>
<.autocomplete id="my-autocomplete"></.autocomplete>
Opens a autocomplete component from a server handler (Socket) or by chaining
onto an existing Phoenix.LiveView.JS pipeline.
Examples
def handle_event("show", _, socket) do
{:noreply, Fluxon.open_autocomplete(socket, "my-autocomplete")}
end
JS.push("logged") |> Fluxon.open_autocomplete("my-autocomplete")
Opens a date picker component by id.
Returns a Phoenix.LiveView.JS struct that dispatches a DOM event to the
target element. The id may be passed as "my-id" or "#my-id"; both
forms resolve to the same target.
Examples
<.button phx-click={Fluxon.open_date_picker("my-date_picker")}>Open</.button>
<.date_picker id="my-date_picker"></.date_picker>
Opens a date picker component from a server handler (Socket) or by chaining
onto an existing Phoenix.LiveView.JS pipeline.
Examples
def handle_event("show", _, socket) do
{:noreply, Fluxon.open_date_picker(socket, "my-date_picker")}
end
JS.push("logged") |> Fluxon.open_date_picker("my-date_picker")
Opens a dialog component by id.
Returns a Phoenix.LiveView.JS struct that dispatches a DOM event to the
target element. The id may be passed as "my-id" or "#my-id"; both
forms resolve to the same target.
Examples
<.button phx-click={Fluxon.open_dialog("my-dialog")}>Open</.button>
<.modal id="my-dialog"></.modal>
Opens a dialog component from a server handler (Socket) or by chaining
onto an existing Phoenix.LiveView.JS pipeline.
Examples
def handle_event("show", _, socket) do
{:noreply, Fluxon.open_dialog(socket, "my-dialog")}
end
JS.push("logged") |> Fluxon.open_dialog("my-dialog")
Opens a dropdown component by id.
Returns a Phoenix.LiveView.JS struct that dispatches a DOM event to the
target element. The id may be passed as "my-id" or "#my-id"; both
forms resolve to the same target.
Examples
<.button phx-click={Fluxon.open_dropdown("my-dropdown")}>Open</.button>
<.dropdown id="my-dropdown"></.dropdown>
Opens a dropdown component from a server handler (Socket) or by chaining
onto an existing Phoenix.LiveView.JS pipeline.
Examples
def handle_event("show", _, socket) do
{:noreply, Fluxon.open_dropdown(socket, "my-dropdown")}
end
JS.push("logged") |> Fluxon.open_dropdown("my-dropdown")
Opens a popover component by id.
Returns a Phoenix.LiveView.JS struct that dispatches a DOM event to the
target element. The id may be passed as "my-id" or "#my-id"; both
forms resolve to the same target.
Examples
<.button phx-click={Fluxon.open_popover("my-popover")}>Open</.button>
<.popover id="my-popover"></.popover>
Opens a popover component from a server handler (Socket) or by chaining
onto an existing Phoenix.LiveView.JS pipeline.
Examples
def handle_event("show", _, socket) do
{:noreply, Fluxon.open_popover(socket, "my-popover")}
end
JS.push("logged") |> Fluxon.open_popover("my-popover")
Opens a select component by id.
Returns a Phoenix.LiveView.JS struct that dispatches a DOM event to the
target element. The id may be passed as "my-id" or "#my-id"; both
forms resolve to the same target.
Examples
<.button phx-click={Fluxon.open_select("my-select")}>Open</.button>
<.select id="my-select"></.select>
Opens a select component from a server handler (Socket) or by chaining
onto an existing Phoenix.LiveView.JS pipeline.
Examples
def handle_event("show", _, socket) do
{:noreply, Fluxon.open_select(socket, "my-select")}
end
JS.push("logged") |> Fluxon.open_select("my-select")
Opens a tags input component by id.
Returns a Phoenix.LiveView.JS struct that dispatches a DOM event to the
target element. The id may be passed as "my-id" or "#my-id"; both
forms resolve to the same target.
Examples
<.button phx-click={Fluxon.open_tags_input("my-tags_input")}>Open</.button>
<.tags_input id="my-tags_input"></.tags_input>
Opens a tags input component from a server handler (Socket) or by chaining
onto an existing Phoenix.LiveView.JS pipeline.
Examples
def handle_event("show", _, socket) do
{:noreply, Fluxon.open_tags_input(socket, "my-tags_input")}
end
JS.push("logged") |> Fluxon.open_tags_input("my-tags_input")
Opens a tooltip component by id.
Returns a Phoenix.LiveView.JS struct that dispatches a DOM event to the
target element. The id may be passed as "my-id" or "#my-id"; both
forms resolve to the same target.
Examples
<.button phx-click={Fluxon.open_tooltip("my-tooltip")}>Open</.button>
<.tooltip id="my-tooltip"></.tooltip>
Opens a tooltip component from a server handler (Socket) or by chaining
onto an existing Phoenix.LiveView.JS pipeline.
Examples
def handle_event("show", _, socket) do
{:noreply, Fluxon.open_tooltip(socket, "my-tooltip")}
end
JS.push("logged") |> Fluxon.open_tooltip("my-tooltip")
Queues a toast notification that survives navigation.
Works with both Plug.Conn (controllers, dead views) and
Phoenix.LiveView.Socket. Toast data rides on Phoenix's flash mechanism,
so it survives redirect/2, push_navigate/2, live_redirect, and
full-page reloads - the same call works everywhere.
Because toast data must serialize through the flash transport,
put_toast/3 only accepts plain values. For richer toasts (HEEx content,
callback actions, loading/resolve), use send_toast/3 instead - those are
in-LiveView only.
Options
:color- one of:info,:success,:warning,:danger, ornilfor the neutral default. Error toasts are announced assertively for screen readers.:description- secondary text rendered below the title.:dismiss_after- auto-dismiss in milliseconds. Defaults to the toaster'sdismiss_after(typically4000). Passnilfor persistent toasts that only go away when the user dismisses them or you calldismiss_toast/2.:dismissible- whether the user can dismiss the toast (X button, swipe, Escape). Defaults totrue.:icon- passfalseto hide the color icon. Custom HEEx icons are not supported via this transport - usesend_toast/3.:action/:actions- one map or a list of maps. Each action map requires:labeland:type. Allowed types here are:link(with exactly one of:href,:navigate, or:patch- mirroring Phoenix's<.link>component) and:dismiss(no other side effect). Optional:position(:inlineor:below, default:below),:variant(outline,solid,soft,surface,ghost,link),:disabled, and:dismiss(defaulttrue; passfalseto keep the toast open after the action fires). Callback actions (type: :event) are not allowed here - usesend_toast/3.:id- custom toast id. An opaque id is generated when omitted. Provide one explicitly when you intend to reference the toast later withdismiss_toast/2orresolve_toast/4.
Setup
Pass @flash to the toaster in your root layout:
<.toaster flash={@flash} />Examples
# Controller - redirect shows the toast on the destination page
conn
|> Fluxon.put_toast("Welcome back!", color: :info)
|> redirect(to: ~p"/")
# Controller - render shows the toast on the rendered page itself
conn
|> Fluxon.put_toast("Could not save", color: :danger)
|> render(:edit, changeset: changeset)
# LiveView handler - survives push_navigate
{:noreply,
socket
|> Fluxon.put_toast("Saved", color: :success)
|> push_navigate(to: ~p"/dashboard")}
# Link action
Fluxon.put_toast(socket, "Account created",
action: %{label: "View profile", type: :link, href: ~p"/profile"})Notes and limits
- Redirect when the toast must survive navigation. Phoenix only
persists flash to the session cookie when the response status is in
300..308. With a 200 render the toast still shows - the rendered response carries the payload and the standalone runtime surfaces it - but it does not survive a further navigation. - Flash list is capped. Phoenix flash rides on the session cookie (~4KB hard limit), so the queued list is capped both by entry count and by encoded byte size. Excess toasts are silently dropped (oldest first) to keep the cookie within budget.
- Signed-token TTL is 60 seconds. For
push_navigate/live_redirect, Phoenix signs the flash with a 60-second TTL. Long-running async work betweenput_toastand the navigation can push the token past expiry. - Unsafe
:hrefschemes are rejected. Onlyhttp,https,mailto,tel,sms, and paths starting with/,#,?, or//are allowed.javascript:,data:,vbscript:, and friends raiseArgumentError.:navigateand:patchaccept only relative paths starting with/,#, or?.
Returns
- For
Phoenix.LiveView.Socket- an updated socket. Chain withpush_navigate/2/redirect/2or return as-is from a handler. - For
Plug.Conn- an updated conn. Chain withredirect/2.
Resolves a previously-shown toast (typically a loading toast) with a new title and, optionally, a new color.
Has three forms, mirroring send_toast/3:
resolve_toast(socket, toast_id, title, opts)- pushes a channel event from ahandle_event/handle_info. Returns the socket.resolve_toast(toast_id, title, opts)- returns aPhoenix.LiveView.JScommand for use inphx-click={...}, resolving the toast with no server round-trip.resolve_toast(%JS{}, toast_id, title, opts)- chains onto an existingJSpipeline.
The :color lives in opts like every other toast helper. Omit it to
keep the toast's current color (e.g. updating the title of a still-loading
toast); pass one to flip it (e.g. color: :success). Accepts the same
options as send_toast/3 for the resolved state - including
:description, :dismiss_after, :action, :dismissible.
Re-uses the toast's existing DOM node when possible; swaps in a new node
when the color changes, so the resolution animates smoothly. Calling this
for a toast id that no longer exists falls through to a fresh
send_toast, so duplicate resolves are harmless.
Examples
# Success
socket = Fluxon.resolve_toast(socket, id, "Done!", color: :success)
# Failure with detail and a retry button
socket =
Fluxon.resolve_toast(socket, id, "Failed",
color: :danger,
description: "Try again.",
action: %{label: "Retry", type: :event, event: "retry"})
# Keep the loading color, just update the title (no color given)
socket = Fluxon.resolve_toast(socket, id, "Still uploading, 80%...")
Shows a rich, in-LiveView toast.
Has three forms - pick by the first argument:
send_toast(socket, title, opts)- pushes a channel event from ahandle_event/handle_info. Survives the request that emits it but disappears on navigation.send_toast(title, opts)- returns aPhoenix.LiveView.JScommand for use inphx-click={...}. Fires a DOM event directly with no server round-trip. The toast payload is rendered server-side at template time, so HEEx in:content/:iconworks the same as the socket form.send_toast(%JS{}, title, opts)- same as the bare form but chains onto an existingJScommand pipeline (JS.push(...) |> Fluxon.send_toast(...)).
Unlike put_toast/3, send_toast does not survive navigation -
pair it with push_navigate/2 or redirect/2 and the toast disappears
with the LiveView. Use put_toast/3 for navigation-spanning
notifications.
Supports every option of put_toast/3, plus:
:content- custom HEEx (~H"...") replacing the title/description block for rich layouts (avatars, multi-line text, custom widgets).:icon- custom HEEx icon, a string of HTML, orfalseto hide. Strings are rendered viainnerHTML; only use values from trusted server-side sources.:action/:actions- may include callback actions (type: :event), link actions (type: :link), and pure-dismiss actions (type: :dismiss). Callbacks push the named:eventto your LiveView viaphx-event. The default is to dismiss the toast after the action fires; passdismiss: falseto keep it open.
Examples
# Server-driven (handle_event)
Fluxon.send_toast(socket, "Item deleted",
action: %{label: "Undo", type: :event, event: "undo", value: %{id: 42}})
# Client-driven via phx-click - no server round-trip
<.button phx-click={Fluxon.send_toast("Copied!", color: :success)}>
Copy
</.button>
# Chained: fire a server event AND show an immediate toast
<.button phx-click={
JS.push("save_draft")
|> Fluxon.send_toast("Saving...", color: :info, dismiss_after: 2_000)
}>
Save
</.button>
# Pure-dismiss action - closes the toast, no other side effect.
# Pair with dismissible: false so the labeled button is the only
# close control (otherwise the X duplicates it).
Fluxon.send_toast(socket, "Welcome aboard",
color: :info,
description: "Tour the dashboard to get started.",
dismissible: false,
action: %{label: "Got it", type: :dismiss, position: :inline})
# Rich HEEx content (works in any form - the ~H renders at the
# call site)
Fluxon.send_toast(socket, "New follower",
content: ~H\"""
<div class="flex items-center gap-2">
<img src={@user.avatar} class="size-6 rounded-full" />
<span>{@user.name}</span>
</div>
\""")
# Multiple actions, inline layout (Cancel + Retry on one row)
Fluxon.send_toast(socket, "Deploy ready",
actions: [
%{label: "Deploy", type: :event, event: "deploy", variant: "solid", position: :inline},
%{label: "Discard", type: :event, event: "discard", variant: "ghost", position: :inline}
])Notes
- Requires a mounted
<.toaster>. The bare and%JS{}forms dispatch a DOM event the toaster hook listens for; if no toaster is on the page (or its LiveView hasn't connected yet) the event has no handler and the toast is dropped. - Same
:hrefvalidation everywhere. Unsafe schemes are rejected at build time regardless of transport. - Vanishes on navigation. After
push_navigate/2, the toast goes with the LiveView. Useput_toast/3if the toast must survive. :content/:iconcapture assigns at the call site. In the bare/JS forms the~His evaluated at template render time, so the content reflects the template's assigns - not whatever assigns are current at the click. Use the socket form if you need to capture click-time assigns.
Shows an indeterminate loading toast, designed to be resolved later via
resolve_toast/4.
Has three forms, mirroring send_toast/3:
send_toast_loading(socket, title, opts)- pushes a channel event from ahandle_event/handle_info. Returns{socket, toast_id}so you can pass the id toresolve_toast/4when the work completes. Auto-generates an id when:idis missing.send_toast_loading(title, opts)- returns aPhoenix.LiveView.JScommand for use inphx-click={...}. The spinner appears with no server round-trip. Requires an explicit:idso the server can resolve it later.send_toast_loading(%JS{}, title, opts)- chains onto an existingJSpipeline (JS.push(...) |> Fluxon.send_toast_loading(...)), so a single click can dispatch a server event AND pop the loading toast at the same instant.
In-LiveView only, like send_toast/3. Defaults to dismissible: false
and dismiss_after: nil (persistent), so the toast stays visible until
you call resolve_toast/4 or dismiss_toast/2. Both defaults can be
overridden via opts. The :color is force-set to :loading.
Examples
# Server-side: returns {socket, id}
def handle_event("upload", _, socket) do
{socket, id} = Fluxon.send_toast_loading(socket, "Uploading...")
Task.start(fn -> upload(socket.assigns.user, id, self()) end)
{:noreply, socket}
end
def handle_info({:upload_done, id}, socket) do
{:noreply, Fluxon.resolve_toast(socket, id, "Upload complete!", color: :success)}
end
# Custom id (useful when the id needs to match an external record)
{socket, "upload-42"} =
Fluxon.send_toast_loading(socket, "Uploading file 42...", id: "upload-42")
# Client-kicked: spinner appears instantly on click, server resolves later
<.button phx-click={
JS.push("upload") |> Fluxon.send_toast_loading("Uploading...", id: "upload-1")
}>
Upload
</.button>
Toggles a autocomplete component by id. Same call shapes as open_autocomplete/1.
Toggles a date picker component by id. Same call shapes as open_date_picker/1.
Toggles a dialog component by id. Same call shapes as open_dialog/1.
Toggles a dropdown component by id. Same call shapes as open_dropdown/1.
Toggles a popover component by id. Same call shapes as open_popover/1.
Toggles a select component by id. Same call shapes as open_select/1.
Toggles a tags input component by id. Same call shapes as open_tags_input/1.
Toggles a tooltip component by id. Same call shapes as open_tooltip/1.