josefrichter

josefrichter

Is there a way to have a flash message disappear (fade out) after a few seconds, please? Can’t find anything in docs nor on internets. Feels like this could be easy in LiveView, maybe I’m just missing the obvious. Thank you.

Showing Posts 1 to 10

sfusato

sfusato

You can achieve that with something like this:

Send a message to self when you use put_flash

Process.send_after(self(), :clear_flash, 5000)

Then, in handle_info:

def handle_info(:clear_flash, socket) do
  {:noreply, clear_flash(socket)}
end
baldwindavid

baldwindavid

That will remove the flash immediately, right? I use some css to accomplish fading out though it is for a different case than flash messages.

@keyframes fade-out {
  from {
    opacity: 1;
  }

  to {
    opacity: 0;
  }
}

.fade-out {
  animation-name: fade-out;
}

.animated {
  animation-duration: 1s;
  animation-fill-mode: both;
}
josefrichter

josefrichter OP

It appears to me, that the process that put the flash message is dead after it e.g. creates a record. Maybe the send needs to go to different process?

sfusato

sfusato

That’s true. If you program the sending to a pid, then push_redirect from the live component, the live view will be shut down and a new one created in its place, thus the old process won’t exist anymore. Changing to push_patch should work.

Also, forgot to mention that you also need to make sure the socket is connected before sending the message:

if connected?(socket), do: ...

@baldwindavid, it will just be removed from the DOM. You could chain together 2 events: 1st fade-out the element (add a css class), then remove it altogether. Worth mentioning that animations are best kept for Javascript, rather than Liveview. You could have a hook on the flash message that will remove itself in 5 seconds with animation effects and everything.

josefrichter

josefrichter OP

Bingo! I’ve combined both of your solutions, and tweaked it a bit. I kept push_redirect rather than push_patch as I was “returning” to index and with push_patch my index of items was not updated.

My workaround is that I actually put the Process.send_after into my mount function, because that’s where I always get back to – so if there’s any new flash message displayed, it gets cleared after 5s. Not sure it’s super robust solution, but this way I need the clear function in one place only, and it works nicely.

And I applied the css animation to nicely fade out the flash, no need for javascript, nor desirable for this simple animation, I think.

GumptionWare

GumptionWare

Hey guys. This thread was very helpful. Many thanks. I see many other threads out there asking this question, and this one seems to be the closest to a clean solution.

I wanted to revisit this topic given more recent Phoenix & LiveView releases. Frankly, I am baffled that such a standard UI behavior expectation is still so hard to find a clean solution for in Phoenix/LiveView. If I am missing that solution, please point me to it.

I just created a fresh Phoenix app and ran mix phx.gen.auth to create a typical starting point to see how Flash messages currently behave. (FYI, it looks like my generator runs created a Phoenix 1.7.10 app running LiveView 0.19.5).

Alas, it appears that nothing has changed. Out of the box, Flash message behavior remains static. The Flash box appears, and it just stays there–until the user clicks the “x” in the box to dismiss it.

The (partial) Solution So Far

Adapting the advice in this thread history, I have been able to get the Flash box to go away after a specified number of milliseconds. In my example app, I have a (generated) LiveView scaffolding for an Alerts table and its LiveViews, so I have a MyApp_web/live/alert_live/index.ex and a MyApp_web/live/form_component.ex that are involved in making updates to Alert records via LiveView interactions.

My list of alerts is driven by this logic in MyApp_web/live/alert_live/index.ex:

defp apply_action(socket, :index, _params) do
    Process.send_after(self(), :clear_flash, 3000) #Clear the flash in 3 seconds
    socket
    |> assign(:page_title, "Listing Alerts")
    |> assign(:alert, socket.assigns.current_user.id)
  end

Because each CRUD action on an Alert gets us back here, I have added the Process.send_after(self(), :clear_flash, 3000) in this function as shown above.

That :clear_flash handle_event function is also in MyApp_web/live/alert_live/index.ex:

 @impl true
  def handle_info(:clear_flash, socket) do
    {:noreply, clear_flash(socket)}
  end

This works. I’m not (yet) using CSS to create a graceful fade-out; the Flash box disappears abruptly after 3 seconds. It is not slick, but it is a huge improvement.

But How Do We Generalize This?

I haven’t wired this up for all the other places CRUD activities take place (like User Settings, for example). This solution will require repeating this logic in all the places put_flash is invoked. To say the most, that is very not DRY.

I asked my AI intern for suggestions, and that advice included writing JavaScript to create a more generalized solution. That strikes me as antithetical to the LiveView vision–particularly for UI behavior users expect–and behavior that is common to most of the other web frameworks out there.

  • To put it bluntly, the out-of-the-box Flash behavior is half-baked/not ready for prime time.

We need to do better than this. I need a solution that is credible to SaaS users, and our community needs a solution that is credible to UI framework adopters.

I’m not just whining here; I am eager to do the work required to help create, document and publicize a generalized solution.

Thanks in advance for your help.

horizon0708

horizon0708

But How Do We Generalize This?

I haven’t wired this up for all the other places CRUD activities take place (like User Settings, for example). This solution will require repeating this logic in all the places put_flash is invoked. To say the most, that is very not DRY.

To keep it dry, maybe have a look at attach_hook/4 in conjunction with on_mount?

To give an example, I have something like this:

  def on_mount(:subscribe_to_runs, _params, _session, socket) do
     # ... 

    socket =
      socket
      |> attach_hook(
        :hide_flash,
        :handle_info,
        &hide_flash/2
      )

    {:cont, socket}
  end

  defp hide_flash(:hide_flash, socket) do
    {:halt, clear_flash(socket)}
  end

And this is mounted to live_session in router.ex

    live_session :app,
      on_mount: [
        {HanekawaWeb.SubscribeToRunsHook, :subscribe_to_runs}
      ] do
      live "/pipelines", PipelineListLiveView
      live "/pipelines/:id", PipelineLiveView
      live "/runs", RunListLiveView
       # ...
    end

Now the logic to hide the flash is in one place.

I do agree that more could be done for flash though!

GumptionWare

GumptionWare

This looks promising! I’ll give it a shot and report back.

HUGE thanks!

sezaru

sezaru

Hey @GumptionWare maybe you will be interested in my library which supports what you want to do and much more: Flashy - A small library to extend LV's flash notifications - #17 by sezaru

GumptionWare

GumptionWare

Thank @sezaru!! Our team will check that out tomorrow. It looks pretty complete.

Where Next? Top

Trending in Questions Top

katta
I having some trouble figuring out if I have set myself too strict of standards for my production server. Currently I can handle 75% of r...
New
achenet
Hello, I’m trying to build a basic Phoenix web-app, and I’d like to use Tailwind. However, when I launch mix phx.server, I get an error...
New
bradley
I really like the adapter patterns that ecto, nebulex, waffle, etc. use and would love find something similar for a key management servic...
New
unaware8150
Hello folks! So at work, we are seeing some situations where we have to define some “fixed” strings that are used across the codebase in...
New
Cxx-mlr
I’m working on a small exercise involving update_in/3, and I came up with this solution: data = %{ name: "Periodic Table", category:...
New
ChrisAmelia
I’ve got trouble wrapping my head around the order in which functions are called in this snippet (from Phoenix’s authentication): toke...
New
dillonoconnor
Is there any way to avoid the Hologram compiler running when using iex? It seems like the front-end code could potentially be disregarded...
New

Other Trending Topics Top

GenericJam
Edit: 2026 May 15 - This post is archived. Mob is alive!! Main docs: mob v0.7.11 — Documentation A bit of explanation for the slightly c...
New
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
budgie
A little off-topic, but I feel like people here have a good head on their shoulders. I used to be quite good at making software. Was luc...
New
KristerV
Hey. Is there anyone here who creates agents in their apps? Not talking about using agents, but creating them. I’m finding it pretty diff...
New
mudasobwa
I fully migrated to my own harness from Anthropic/Gemini and I think it’s time to share it. Welcome DSH, the DeepSeek Harness, fully writ...
New
mcass19
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews