In a previous video, we explored how to implement modals using Hotwire. In this tutorial, we will dive into adding Flash messages to improve the user experience in our application. Flash messages provide immediate feedback when a user performs an action, making it more apparent that their changes have been saved.

We'll be starting with a fresh Rails app where Flash messages aren't yet implemented. Our goal is to show Flash messages when the user updates their profile information in a modal. The updates should be made in ProfilesController.

Displaying Flash Messages in Our Layout

Go to the ProfilesController. After successfully updating the profile, set a Flash notice with the message "Profile was successfully updated.".

In our application layout file, we need to include a partial to render the Flash messages. Create a new partial view file app/views/shared/_flash.html.erb :

<%# app/views/shared/_flash.html.erb %>
<% flash.each do |key, value| %>
  <div>
    <%= value %>
  </div>
<% end %>

Include the partial in our application layout with <%= render "shared/flash" %>. Save the changes and update the profile in the app. You should see the message "Profile was successfully updated".

Styling Flash Messages

To improve the appearance of our Flash messages, style them with Tailwind CSS. Make the message fixed position, display it in the top right corner of the screen, and add some padding and width:

<%# app/views/shared/_flash.html.erb %>
<div class="flex items-center fixed top-5 right-5 bg-blue-100 text-blue-700 py-3 px-5 rounded-lg">
  <%= value %>
</div>

Adding a Close Button

To provide an option to dismiss the message, add a close button using Heroicons. They offer various icons that can be easily incorporated into the project. Choose the "X" icon, copy its SVG code, and paste it into our Flash message. You may need to add a little margin on the left to space it out from the text and make the Flash message a Flexbox container:

<%# app/views/shared/_flash.html.erb %>
<div class="flex items-center fixed top-5 right-5 bg-blue-100 text-blue-700 py-3 px-5 rounded-lg">
  <%= value %>
  <button type="button">
      <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
      </svg>
  </button>
</div>

Dismissing Flash Messages with Stimulus

To enable the close button, we will create a Stimulus controller called FlashController. Replace the default hello_controller.js with flash_controller.js:

// app/javascript/controllers/flash_controller.js
import { Controller } from "stimulus";

export default class extends Controller {
  dismiss() {
    this.element.remove();
  }
}

Run the bin/rails stimulus:manifest:update task to register the new controller.

Wire up the Stimulus controller to our Flash messages by adding the data-controller attribute to the Flash message div and the data-action attribute to the close button:

<div data-controller="flash" class="flex items-center fixed top-5 right-5 bg-blue-100 text-blue-700 py-3 px-5 rounded-lg">
  <%= value %>
  <button type="button" data-action="flash#dismiss">
      <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
      </svg>
  </button>
</div>

Now, the close button should work, and Flash messages will be dismissed when clicked.

Auto-Hiding Flash Messages

It's nice to have Flash messages automatically disappear after a few seconds. To achieve this, add the connect() method to our flash_controller.js and call the dismiss() method after a setTimeout of 3 seconds:

connect() {
  setTimeout(() => {
    this.dismiss();
  }, 3000);
}

Handling Flash Error Messages

Lastly, let's take a look at handling error messages. If we change the Flash notice to Flash error in the ProfilesController, it will still have the same blue styling. To handle different types of Flash messages, create a Rails helper to determine the appropriate CSS class:

# app/helpers/flash_helper.rb
module FlashHelper
  def classes_for_flash(flash_type)
    case flash_type.to_sym
    when :error
      "bg-red-100 text-red-700"
    else
      "bg-blue-100 text-blue-700"
    end
  end
end

Replace the hardcoded styling in the Flash message markup with our helper method:

<%# app/views/shared/_flash.html.erb %>
<% flash.each do |key, value| %>
  <div data-controller="flash" class="flex items-center fixed top-5 right-5 <%= classes_for_flash(key) %> py-3 px-5 rounded-lg">
    <div class="mr-4"><%= value %></div>

    <button type="button" data-action="flash#dismiss">
      <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
      </svg>
    </button>
  </div>
<% end %>

With this, error messages will have a red background and text.

Wrapping Up

Flash messages provide valuable feedback to users, knowing that their actions were successful or that errors occured. Using Hotwire, Stimulus, and Rails helpers, we can create a seamless experience with customisable styling.

Stay tuned for more Hotwire content!

Source code before:
https://github.com/phawk/hotwire-demo/tree/turbo_modals

Source code after: 
https://github.com/phawk/hotwire-demo/tree/turbo_flash_messages

Discussion (0)

To comment you need to sign up for a free account or sign in.

Get new videos in your inbox weekly!

Be the first to hear about new courses and videos launching. You’ll only receive relevant news, no spam.