Packages
Server-rendered toast notifications for Phoenix LiveView.
Retired package: Deprecated - Experimental release, please use 0.0.3 or later
Current section
Files
Jump to
Current section
Files
lib/toast.ex
defmodule Toast do
@moduledoc """
Server-rendered toast notifications for Phoenix LiveView.
Toast provides a simple, server-controlled toast notification system for Phoenix LiveView
applications. All state is managed on the server using LiveView streams, with a minimal
JavaScript hook for animations and interactions.
## Installation
Add `toast` to your dependencies in `mix.exs`:
def deps do
[
{:toast, "~> 0.0.2"}
]
end
## Setup
1. Import the JavaScript hook in your `app.js`:
import Toast from "../deps/toast/assets/js/toast.js";
let liveSocket = new LiveSocket("/live", Socket, {
hooks: { Toast }
});
2. Import the CSS in your `app.css`:
@import "../deps/toast/assets/css/toast.css";
3. Add the toast container to your root layout:
<Toast.toast_group flash={@flash} />
## Basic Usage
Send toasts from your LiveView:
def handle_event("save", _params, socket) do
Toast.send_toast(:success, "Changes saved!")
{:noreply, socket}
end
## Toast Types
- `:info` - Blue informational messages
- `:success` - Green success messages
- `:error` - Red error messages
- `:warning` - Yellow warning messages
- `:loading` - Loading state with spinner
- `:default` - Default neutral style
## Options
Configure individual toasts with:
Toast.send_toast(:success, "Message",
title: "Success!",
description: "Additional details",
duration: 10_000,
action: %{
label: "Undo",
event: "undo_action"
}
)
See the documentation for `send_toast/3` for all available options.
"""
use Phoenix.Component
defstruct [
:id,
:type,
:message,
:title,
:description,
:duration,
:action,
:icon,
:close_button,
:position,
:important
]
@type t :: %__MODULE__{
id: String.t(),
type: :info | :success | :error | :warning | :loading | :default,
message: String.t(),
title: String.t() | nil,
description: String.t() | nil,
duration: integer() | nil,
action: map() | nil,
icon: String.t() | nil,
close_button: boolean(),
position: atom() | nil,
important: boolean()
}
@doc """
Renders the toast notification container.
This is a convenience function component that wraps the Toast.LiveComponent.
It can be used directly in your templates with the component syntax.
## Examples
<Toast.toast_group
flash={@flash}
/>
<Toast.toast_group
flash={@flash}
position="top-right"
theme="dark"
rich_colors={true}
max_toasts={5}
/>
## Attributes
* `:id` - The ID of the toast group container (default: "toast-group")
* `:flash` - The flash assigns from the socket
* `:position` - Position of toasts: "top-left", "top-center", "top-right", "bottom-left", "bottom-center", "bottom-right" (default: "bottom-right")
* `:theme` - Theme: "light" or "dark" (default: "light")
* `:rich_colors` - Whether to use rich colors for different toast types (default: false)
* `:max_toasts` - Maximum number of toasts to display (default: 3)
"""
attr(:id, :string, default: "toast-group")
attr(:flash, :map, required: false)
attr(:position, :string, default: "bottom-right")
attr(:theme, :string, default: "light")
attr(:rich_colors, :boolean, default: false)
attr(:max_toasts, :integer, default: 3)
def toast_group(assigns) do
~H"""
<.live_component
module={Toast.LiveComponent}
id={@id}
flash={@flash}
position={@position}
theme={@theme}
rich_colors={@rich_colors}
max_toasts={@max_toasts}
/>
"""
end
@doc """
Sends a toast notification to the LiveComponent.
## Examples
Toast.send_toast(:info, "Operation completed!")
Toast.send_toast(:error, "Something went wrong", title: "Error", duration: 10_000)
"""
def send_toast(type, message, opts \\ []) do
toast = build_toast(type, message, opts)
Phoenix.LiveView.send_update(self(), Toast.LiveComponent,
id: "toast-group",
toast: toast
)
end
@doc """
Sends a toast notification and returns the socket for piping.
This is a convenience function for use in pipelines.
## Examples
socket
|> assign(:user, user)
|> put_toast(:success, "Profile updated!")
|> push_navigate(to: ~p"/profile")
"""
def put_toast(socket, type, message, opts \\ []) do
send_toast(type, message, opts)
socket
end
@doc """
Updates an existing toast by ID.
## Examples
Toast.update_toast("toast-123", message: "Updated message", type: :success)
Toast.update_toast("toast-123", title: "New Title", duration: 10_000)
"""
def update_toast(toast_id, updates) do
Phoenix.LiveView.send_update(self(), Toast.LiveComponent,
id: "toast-group",
update_toast: %{id: toast_id, updates: updates}
)
end
@doc """
Clears a specific toast by ID.
"""
def clear_toast(id) do
Phoenix.LiveView.send_update(self(), Toast.LiveComponent,
id: "toast-group",
clear: id
)
end
@doc """
Clears all toasts.
"""
def clear_all_toasts() do
Phoenix.LiveView.send_update(self(), Toast.LiveComponent,
id: "toast-group",
clear_all: true
)
end
defp build_toast(type, message, opts) do
%__MODULE__{
id: opts[:id] || generate_id(),
type: type,
message: message,
title: opts[:title],
description: opts[:description],
duration: opts[:duration] || 6000,
action: opts[:action],
icon: opts[:icon],
close_button: Keyword.get(opts, :close_button, true),
position: opts[:position],
important: Keyword.get(opts, :important, false)
}
end
defp generate_id do
"toast-#{:crypto.strong_rand_bytes(8) |> Base.encode16(case: :lower)}"
end
end