After sharing how I implemented automatic flash dismissal in Phoenix LiveView, I realized there’s an even cleaner way to do it — by using Tailwind CSS animations instead of setting styles manually in JavaScript.

This approach makes the code more declarative, customizable, and easier to maintain. Let’s see how it works!

Step 1: Simplify the hook

Instead of changing opacity directly in JavaScript, we can simply add a CSS class that triggers a fade-out animation.

Here’s the updated assets/js/hooks/auto-dismiss-flash.js:

export default {
  mounted() {
    setTimeout(() => {
      this.el.classList.add("fade-out");
    }, 5000); // Start fading out after 5 seconds

    this.el.addEventListener("animationend", () => {
      this.el.remove();
    });
  },
};

What’s different?

  • After 5 seconds, we add the fade-out class.
  • Once the animation finishes, the element is automatically removed from the DOM.

The hook itself stays simple — no need to touch inline styles anymore.

Step 2: Define the Tailwind animation

Next, we define the fade-out animation in our Tailwind setup.

In assets/css/app.css (or wherever your Tailwind layers are defined), add:

@tailwind base;
@tailwind components;
@tailwind utilities;

@layer utilities {
  @keyframes fadeOut {
    from { opacity: 1; }
    to { opacity: 0; }
  }

  .fade-out {
    animation: fadeOut 0.5s ease forwards;
  }
}

This creates:

  • A fadeOut animation that gradually reduces opacity,
  • A .fade-out utility class that plays it over 0.5 seconds.

Now you can control the animation timing and easing in one central place instead of scattering it inside JavaScript.

Step 3: Attach the hook as before

No changes are needed to the flash component itself. It’s still as simple as:

<div
  id={@id}
  phx-hook="AutoDismissFlash"
  ...
>
  ...
</div>

By keeping the phx-hook="AutoDismissFlash", your flashes will now fade out smoothly after a few seconds.

Why use Tailwind animations?

Manual Approach Tailwind Animation
Styles are set manually in JS Styles are handled declaratively via CSS
Harder to tweak duration and easing Easy to adjust globally
JavaScript needs to manage fade and removal CSS handles the animation, JS only removes the element after animation
More fragile and harder to reuse Clean, consistent, and easily customizable

In short: fewer moving parts, better maintainability.

Bonus: slide and fade Effect ✨

If you want an even smoother effect where the flash message slides up while fading out, you can tweak the animation:

@layer utilities {
  @keyframes fadeSlideUp {
    0% { opacity: 1; transform: translateY(0); }
    100% { opacity: 0; transform: translateY(-10px); }
  }

  .fade-out {
    animation: fadeSlideUp 0.5s ease forwards;
  }
}

This makes the flash gently float upwards while disappearing — giving the UI an even more polished feeling.