From a41110bc7f9ba0f35b77dd1bc4fa6c2d00097fe6 Mon Sep 17 00:00:00 2001
From: Andrew
Date: Fri, 28 Aug 2026 16:42:07 -0400
Subject: [PATCH 1/3] Update CHANGELOG.md
---
CHANGELOG.md | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c3eb0ec..80f7563 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,16 @@ All notable changes to this project will be documented in this file.
Note that the versions prior to `0.6.0` are very unstable.
+## [v0.10.0] (unreleased)
+
+Note: this release includes breaking changes involving translation. The library no longer calls `gettext` functions on
+dynamic strings passed to `put_toast` and `send_toast`.
+
+### Changed
+
+- [Translation behavior](https://github.com/srcrip/live_toast/pull/78): translation of LiveToast's built-in connection notices is now opt-in; configure `gettext_backend` to enable it. `send_toast/3`, `put_toast/4`, and custom connection-notification copy now render the supplied message and title unchanged, so translate application-owned copy before passing it to LiveToast.
+- [TypeScript compatibility](https://github.com/srcrip/live_toast/pull/77): LiveToast no longer augments the global `HTMLElement` interface, and the package now ships and exposes its TypeScript declarations.
+
## [v0.1.0] (2024-03-06)
🚀 Initial release.
From 2c30f02cf9ba3bbae8f91e7afaf10778c94f48e8 Mon Sep 17 00:00:00 2001
From: Andrew
Date: Fri, 28 Aug 2026 16:47:04 -0400
Subject: [PATCH 2/3] Render flashes with host toast component
---
README.md | 10 ++-
demo/lib/demo_web/components/layouts.ex | 13 ++++
.../demo_web/components/layouts/app.html.heex | 3 +
.../live/tabs/customization.html.heex | 16 ++++-
demo/test/demo_web/live/send_toast_test.exs | 62 +++++++++++++++++++
lib/live_toast.ex | 10 ++-
lib/live_toast/components.ex | 50 +++++++++++----
lib/live_toast/live_component.ex | 2 +
8 files changed, 149 insertions(+), 17 deletions(-)
diff --git a/README.md b/README.md
index cbba910..ff8ead0 100644
--- a/README.md
+++ b/README.md
@@ -316,9 +316,9 @@ classes; use a custom component function for the icon, title, body, action, and
### Default custom toast component
-Pass `toast_component_fn` to `LiveToast.toast_group` when all programmatic toasts in that host should use the same
-custom component. A `component:` passed to an individual `send_toast/3` call takes precedence. This host default does
-not change Phoenix flash or connection-notice rendering.
+Pass `toast_component_fn` to `LiveToast.toast_group` when programmatic toasts and Phoenix flashes in that host should
+use the same custom component. A `component:` passed to an individual `send_toast/3` call takes precedence for that
+toast. Connection notices continue to use their default content or the corresponding slot.
```heex
```
+`flash_group_id` optionally adds an addressable container around only the Phoenix flashes. Programmatic toasts remain
+outside that container.
+
```elixir
LiveToast.send_toast(:info, "The message was sent.", title: "Sent")
```
diff --git a/demo/lib/demo_web/components/layouts.ex b/demo/lib/demo_web/components/layouts.ex
index 27a66b5..1070eba 100644
--- a/demo/lib/demo_web/components/layouts.ex
+++ b/demo/lib/demo_web/components/layouts.ex
@@ -35,6 +35,19 @@ defmodule DemoWeb.Layouts do
]
end
+ attr(:kind, :atom, required: true)
+ attr(:title, :string, default: nil)
+ attr(:body, :any, required: true)
+
+ def demo_toast_component_fn(assigns) do
+ ~H"""
+
+
{@title}
+
{@body}
+
+ """
+ end
+
attr(:notice, :map, required: true)
def connection_notice(assigns) do
diff --git a/demo/lib/demo_web/components/layouts/app.html.heex b/demo/lib/demo_web/components/layouts/app.html.heex
index e69fe7d..c93675f 100644
--- a/demo/lib/demo_web/components/layouts/app.html.heex
+++ b/demo/lib/demo_web/components/layouts/app.html.heex
@@ -2,6 +2,9 @@
toast_component_fn
on toast_group
- to use it for every programmatic toast in that host.
+ to use it for every programmatic toast and Phoenix flash in that host.
+
diff --git a/demo/test/demo_web/live/send_toast_test.exs b/demo/test/demo_web/live/send_toast_test.exs
index ff1d8ad..5790247 100644
--- a/demo/test/demo_web/live/send_toast_test.exs
+++ b/demo/test/demo_web/live/send_toast_test.exs
@@ -156,6 +156,28 @@ defmodule DemoWeb.SendToastTest do
end
end
+ defmodule FlashComponentLive do
+ @moduledoc false
+
+ use Phoenix.LiveView
+
+ def mount(_params, _session, socket) do
+ {:ok, Phoenix.LiveView.put_flash(socket, :info, "Rendered from a live flash.")}
+ end
+
+ def render(assigns) do
+ ~H"""
+
+ """
+ end
+ end
+
defmodule ClientToastLive do
@moduledoc false
@@ -262,6 +284,24 @@ defmodule DemoWeb.SendToastTest do
"""
end
+ defp dead_flash_component_host(assigns) do
+ ~H"""
+
+ """
+ end
+
+ def flash_component(assigns) do
+ ~H"""
+
{@body}
+ """
+ end
+
describe "LiveToast.send_toast/3" do
test "renders info toast", %{conn: conn} do
{:ok, view, _html} = live_isolated(conn, TestLive)
@@ -344,6 +384,28 @@ defmodule DemoWeb.SendToastTest do
end
end
+ describe "Phoenix flashes" do
+ test "uses the host component in a live host", %{conn: conn} do
+ {:ok, view, html} = live_isolated(conn, FlashComponentLive)
+
+ assert html =~ ~s(id="live-flashes")
+ assert html =~ ~s(data-flash-renderer="custom")
+ assert html =~ "Rendered from a live flash."
+ assert has_element?(view, "#live-flashes [data-kind=info]")
+ end
+
+ test "uses the host component in a dead host" do
+ html =
+ render_component(&dead_flash_component_host/1,
+ flash: %{"error" => "Rendered from a dead flash."}
+ )
+
+ assert html =~ ~s(id="dead-flashes")
+ assert html =~ ~s(data-flash-renderer="custom")
+ assert html =~ "Rendered from a dead flash."
+ end
+ end
+
describe "client toast API" do
test "renders a client toast with supported options", %{conn: conn} do
{:ok, view, _html} = live_isolated(conn, ClientToastLive)
diff --git a/lib/live_toast.ex b/lib/live_toast.ex
index 054befc..3fb62ff 100644
--- a/lib/live_toast.ex
+++ b/lib/live_toast.ex
@@ -298,7 +298,12 @@ defmodule LiveToast do
attr(:toast_component_fn, :any,
default: nil,
- doc: "default component function used to render programmatic toasts"
+ doc: "default component function used to render programmatic toasts and Phoenix flashes"
+ )
+
+ attr(:flash_group_id, :string,
+ default: nil,
+ doc: "optional id for a container around Phoenix flashes"
)
attr :toasts_sync, :list, required: true, doc: "toasts that get synchronized when calling `put_toast`"
@@ -332,6 +337,7 @@ defmodule LiveToast do
client_error_delay={@client_error_delay}
toast_class_fn={@toast_class_fn}
toast_component_fn={@toast_component_fn}
+ flash_group_id={@flash_group_id}
group_class_fn={@group_class_fn}
connection_notifications={@connection_notifications}
client_error={@client_error}
@@ -345,7 +351,9 @@ defmodule LiveToast do
corner={@corner}
flash_duration={@flash_duration}
toast_class_fn={@toast_class_fn}
+ toast_component_fn={@toast_component_fn}
group_class_fn={@group_class_fn}
+ flash_group_id={@flash_group_id}
client_error_delay={@client_error_delay}
connection_notifications={@connection_notifications}
client_error={@client_error}
diff --git a/lib/live_toast/components.ex b/lib/live_toast/components.ex
index b50dfc0..b19d009 100644
--- a/lib/live_toast/components.ex
+++ b/lib/live_toast/components.ex
@@ -133,6 +133,13 @@ defmodule LiveToast.Components do
doc: "function to override the toast classes"
)
+ attr(:toast_component_fn, :any,
+ default: nil,
+ doc: "component function used to render Phoenix flash content"
+ )
+
+ attr(:id, :string, default: nil, doc: "optional id for the flash-only container")
+
attr(:connection_notifications, :any,
default: %{},
doc: "false disables connection-state notifications; a map overrides their copy and kind"
@@ -150,18 +157,10 @@ defmodule LiveToast.Components do
assigns = assign(assigns, :connection_notifications, connection_notifications(assigns.connection_notifications))
~H"""
- <.toast
- :for={level <- @kinds}
- data-component="flash"
- corner={@corner}
- toast_class_fn={@toast_class_fn}
- flash_duration={@flash_duration}
- duration={0}
- kind={level}
- title={String.capitalize(to_string(level))}
- phx-update="ignore"
- flash={@f}
- />
+
+ <.flash_toasts {assigns} />
+
+ <.flash_toasts :if={!@id} {assigns} />
<%= if @connection_notifications do %>
<.toast
data-component="flash"
@@ -224,6 +223,24 @@ defmodule LiveToast.Components do
"""
end
+ defp flash_toasts(assigns) do
+ ~H"""
+ <.toast
+ :for={level <- @kinds}
+ data-component="flash"
+ corner={@corner}
+ toast_class_fn={@toast_class_fn}
+ component={@toast_component_fn}
+ flash_duration={@flash_duration}
+ duration={0}
+ kind={level}
+ title={String.capitalize(to_string(level))}
+ phx-update="ignore"
+ flash={@f}
+ />
+ """
+ end
+
defp duration_value(:infinity), do: "Infinity"
defp duration_value(duration), do: duration
@@ -247,6 +264,13 @@ defmodule LiveToast.Components do
doc: "function to override the toast classes"
)
+ attr(:toast_component_fn, :any,
+ default: nil,
+ doc: "component function used to render Phoenix flash content"
+ )
+
+ attr(:flash_group_id, :string, default: nil, doc: "optional id for the flash-only container")
+
attr(:client_error_delay, :integer, default: 3000, doc: "adds a delay before the disconnected client error is shown")
attr(:flash_duration, :integer, default: 0, doc: "if provided clears flash after provided milliseconds")
@@ -269,6 +293,8 @@ defmodule LiveToast.Components do
corner={@corner}
flash_duration={@flash_duration}
toast_class_fn={@toast_class_fn}
+ toast_component_fn={@toast_component_fn}
+ id={@flash_group_id}
client_error_delay={@client_error_delay}
connection_notifications={@connection_notifications}
client_error={@client_error}
diff --git a/lib/live_toast/live_component.ex b/lib/live_toast/live_component.ex
index 5f9e52c..171f12c 100644
--- a/lib/live_toast/live_component.ex
+++ b/lib/live_toast/live_component.ex
@@ -141,6 +141,8 @@ defmodule LiveToast.LiveComponent do
corner={@corner}
flash_duration={@flash_duration}
toast_class_fn={@toast_class_fn}
+ toast_component_fn={@toast_component_fn}
+ id={@flash_group_id}
client_error_delay={@client_error_delay}
connection_notifications={@connection_notifications}
client_error={@client_error}
From 61c6e7b2eb439a09ade98396ab168945bed9ed3d Mon Sep 17 00:00:00 2001
From: Andrew
Date: Fri, 28 Aug 2026 16:51:23 -0400
Subject: [PATCH 3/3] Allow live flash updates
---
demo/test/demo_web/live/send_toast_test.exs | 16 ++++++++++++----
lib/live_toast/components.ex | 1 -
2 files changed, 12 insertions(+), 5 deletions(-)
diff --git a/demo/test/demo_web/live/send_toast_test.exs b/demo/test/demo_web/live/send_toast_test.exs
index 5790247..f7c91f3 100644
--- a/demo/test/demo_web/live/send_toast_test.exs
+++ b/demo/test/demo_web/live/send_toast_test.exs
@@ -161,8 +161,10 @@ defmodule DemoWeb.SendToastTest do
use Phoenix.LiveView
- def mount(_params, _session, socket) do
- {:ok, Phoenix.LiveView.put_flash(socket, :info, "Rendered from a live flash.")}
+ def mount(_params, _session, socket), do: {:ok, socket}
+
+ def handle_event("show_flash", _params, socket) do
+ {:noreply, Phoenix.LiveView.put_flash(socket, :info, "Rendered from a live flash.")}
end
def render(assigns) do
@@ -174,6 +176,7 @@ defmodule DemoWeb.SendToastTest do
toast_component_fn={&DemoWeb.SendToastTest.flash_component/1}
flash_group_id="live-flashes"
/>
+
"""
end
end
@@ -389,8 +392,13 @@ defmodule DemoWeb.SendToastTest do
{:ok, view, html} = live_isolated(conn, FlashComponentLive)
assert html =~ ~s(id="live-flashes")
- assert html =~ ~s(data-flash-renderer="custom")
- assert html =~ "Rendered from a live flash."
+ refute html =~ ~s(data-flash-renderer="custom")
+
+ view
+ |> element("button", "Show Flash")
+ |> render_click()
+
+ assert render(view) =~ "Rendered from a live flash."
assert has_element?(view, "#live-flashes [data-kind=info]")
end
diff --git a/lib/live_toast/components.ex b/lib/live_toast/components.ex
index b19d009..fb9e18c 100644
--- a/lib/live_toast/components.ex
+++ b/lib/live_toast/components.ex
@@ -235,7 +235,6 @@ defmodule LiveToast.Components do
duration={0}
kind={level}
title={String.capitalize(to_string(level))}
- phx-update="ignore"
flash={@f}
/>
"""