Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save secretpray/f5a56475d7abd06b9ebf7f7c72040f1e to your computer and use it in GitHub Desktop.
Save secretpray/f5a56475d7abd06b9ebf7f7c72040f1e to your computer and use it in GitHub Desktop.
Autohide flash message (Rails 7, Tailwind, Stimulus)
clip.mp4

app/views/layouts/application.html.erb

  <body class="min-h-screen relative">
    <%= render "layouts/flash" %>
  </body>

app/views/layouts/_flash.html.erb

<% flash.each do |type, message| %>
  <div class="fixed inset-x-0 top-0 flex items-end justify-right px-4 py-5 sm:p-5 justify-end z-30 pointer-events-none">
    <div
        data-controller="removeable"
        data-removeable-show-class="translate-x-0 opacity-75"
        data-removeable-hide-class="translate-x-full opacity-0"
        class="max-w-sm w-full shadow-lg px-4 py-2 rounded relative bg-white dark:bg-gray-600 border-l-8 border-pink-800 text-gray-600 pointer-events-auto transition translate-x-full transform ease-in-out duration-1000 opacity-0">
      <div class="p-2">
        <div class="flex items-start">
          <div class="ml-3 w-0 flex-1">
            <p class="text-sm leading-5 font-medium">
              <%= content_tag :div, message, class: 'dark:text-gray-300' %>
            </p>
          </div>
          <div class="ml-4 flex-shrink-0 flex">
            <button data-action="removeable#close" 
                    class="inline-flex dark:text-gray-300 text-gray-500 focus:outline-none dark:focus:text-gray-400 focus:text-gray-600 top-1" 
                    style='margin-top: 4px;'>
              <svg class="h-4 w-4" viewBox="0 0 20 20" fill="currentColor">
                <path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"/>
              </svg>
            </button>
          </div>
        </div>
      </div>
    </div>
  </div>
<% end %>

app/javascript/controllers/removeable_controller.js

import { Controller } from "@hotwired/stimulus";

// Connects to data-controller="removeable"
export default class extends Controller {
  static values = {
    showDelay: { type: Number, default: 200 },
    removeDelay: { type: Number, default: 5000 },
    dismissAfter: { type: Boolean, default: true }
  }
  static classes = [
    "show", 
    "hide"
  ]

  initialize() {
    this.hide()
  }

  connect() {
    // Auto show (default hidden)
    setTimeout(() => {
      this.show();
      // Auto dismiss if defined
      if (this.dismissAfterValue) {
        setTimeout(() => {
          this.close();
        }, this.removeDelayValue);
      }
    }, this.showDelayValue);
  }

  close() {
    this.hide()

    setTimeout(() => {
      this.element.remove()
    }, this.removeDelayValue)
  }

  show() {
    this.element.classList.add(...this.showClasses)
    this.element.classList.remove(...this.hideClasses)
  }

  hide() {
    this.element.classList.add(...this.hideClasses)
    this.element.classList.remove(...this.showClasses)
  }
}
@yshmarov
Copy link

yshmarov commented Sep 6, 2023

You don't need to write in controllers or turbo_stream.erb a separate turbo_render method for flash render. It is enough to create a new application.turbo_stream.erb file in the "app/views/layouts" folder with the following content:

<%= turbo_stream.append :flash do %>
  <%= render partial: "layouts/flash" %>
<% end %>

<%= yield %>

and flash drives will be automatically rendered

PS It does not conflict with application.html.erb

@secretpray why do we need the <%= yield %>???? 😱

@yshmarov
Copy link

yshmarov commented Sep 6, 2023

ok... with yield, tests are passing. without, tests are failing

Screenshot 2023-09-06 at 23 13 44

@secretpray
Copy link
Author

secretpray commented Oct 2, 2023

<%= yield %>

is needed to render everything else except for the flashes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment