DEV Community

Nikola Djordjevic
Nikola Djordjevic

Posted on

๐Ÿš€ Auto-Clearing Flash Messages in Phoenix LiveView (with a Visual Countdown!)

LiveView gives us beautiful declarative ways to build interactive UIs without writing much JS. But one thing developers often want is this:

โœ… A flash message that shows up, waits a few seconds, fades away โ€” and shows a countdown line while it's visible.

Hereโ€™s how to do it with almost no JS and a sprinkle of Tailwind + raw CSS.


๐Ÿ”ง 1. Add the Flash Component

In your LiveView or component module (core_components.ex), define a flash like this if it doesn't exist already:

def flash(assigns) do
  assigns = assign_new(assigns, :id, fn -> "flash-#{assigns.kind}" end)

  ~H"""
  <div
    :if={msg = render_slot(@inner_block) || Phoenix.Flash.get(@flash, @kind)}
    id={@id}
    phx-hook="AutoClearFlash"
    phx-click={JS.push("lv:clear-flash", value: %{key: @kind}) |> hide("##{@id}")}
    role="alert"
    class={[
      "fixed top-2 right-2 mr-2 w-80 sm:w-96 z-50 rounded-lg p-3 ring-1",
      @kind == :info && "bg-sky-50 text-blue-500 ring-blue-500 fill-blue-900",
      @kind == :success && "bg-emerald-50 text-emerald-800 ring-emerald-500 fill-cyan-900",
      @kind == :warn && "bg-amber-50 text-amber-900 shadow-md ring-amber-500 fill-amber-900",
      @kind == :error && "bg-rose-50 text-rose-900 shadow-md ring-rose-500 fill-rose-900"
    ]}
    {@rest}
  >
    <p :if={@title} class="flex items-center gap-1.5 text-sm font-semibold leading-6">
      <.icon :if={@kind == :info} name="hero-information-circle-mini" class="h-4 w-4" />
      <.icon :if={@kind == :success} name="hero-check-circle-mini" class="h-4 w-4" />
      <.icon :if={@kind == :warn} name="hero-exclamation-circle-mini" class="h-4 w-4" />
      <.icon :if={@kind == :error} name="hero-exclamation-circle-mini" class="h-4 w-4" />
      {@title}
    </p>
    <p class="mt-2 text-sm leading-5">{msg}</p>
    <button type="button" class="group absolute top-1 right-1 p-2" aria-label={gettext("close")}>
      <.icon name="hero-x-mark-solid" class="h-5 w-5 opacity-40 group-hover:opacity-70" />
    </button>
  </div>
  """
end
Enter fullscreen mode Exit fullscreen mode

๐Ÿง  2. Auto-dismiss via Hook

Add a small JS hook (hooks.js):

let Hooks = {}
Hooks.AutoClearFlash = {
  mounted() {
    const ignoredIDs = ["client-error", "server-error"];
    if (ignoredIDs.includes(this.el.id)) return;

    setTimeout(() => this.el.click(), 2500);
  }
};

export default Hooks;
Enter fullscreen mode Exit fullscreen mode

Hook it up in your LiveSocket config:

import Hooks from "./hooks";
let liveSocket = new LiveSocket("/live", Socket, { hooks: { AutoClearFlash }, ... });
Enter fullscreen mode Exit fullscreen mode

๐ŸŽจ 3. Visual Countdown with Raw CSS

Inside your app.css, add this keyframes animation


@keyframes countdown {
  from { width: 100%; }
  to { width: 0%; }
}
Enter fullscreen mode Exit fullscreen mode

โณ 4. Countdown bar

Expand your flash component with this countdown bar for beautiful visual effect. Add it just at the end of your flash component.

<div class="mt-2 h-1 w-full overflow-hidden rounded-full bg-white/30">
  <div class={[
    "h-full animate-[countdown_2.5s_linear_forwards]",
    @kind == :info && "bg-blue-500",
    @kind == :success && "bg-emerald-500",
    @kind == :warn && "bg-amber-500",
    @kind == :error && "bg-rose-500"
  ]} />
</div>
Enter fullscreen mode Exit fullscreen mode

โœ… That's It!

You now have:

  • A flash that disappears after 2.5s
  • A smooth fade-out animation
  • A subtle countdown bar like a fuse burning out

Let LiveView do the heavy lifting โœจ


๐Ÿ’ฌ Got ideas for variations (e.g. pause on hover, different timers per flash type)? Let me know in the comments!

Tiugo image

Fast, Lean, and Fully Extensible

CKEditor 5 is built for developers who value flexibility and speed. Pick the features that matter, drop the ones that donโ€™t and enjoy a high-performance WYSIWYG that fits into your workflow

Start now

Top comments (0)

Neon image

Next.js applications: Set up a Neon project in seconds

If you're starting a new project, Neon has got your databases covered. No credit cards. No trials. No getting in your way.

Get started โ†’

๐Ÿ‘‹ Kindness is contagious

Engage with a wealth of insights in this thoughtful article, cherished by the supportive DEV Community. Coders of every background are encouraged to bring their perspectives and bolster our collective wisdom.

A sincere โ€œthank youโ€ often brightens someoneโ€™s dayโ€”share yours in the comments below!

On DEV, the act of sharing knowledge eases our journey and forges stronger community ties. Found value in this? A quick thank-you to the author can make a world of difference.

Okay