Flash messages with Hotwire
Related videos
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