HEY-style Pop-ups Using Hotwire

Disclaimer: It should be noted that the provided HTML fails to implement the necessary ARIA attributes required for accessibility. These attributes will need to be added to any implementation of this markup in order to be accessible to screen readers…


This content originally appeared on DEV Community and was authored by Jacob Daddario

Disclaimer: It should be noted that the provided HTML fails to implement the necessary ARIA attributes required for accessibility. These attributes will need to be added to any implementation of this markup in order to be accessible to screen readers.

Anyone who's used Basecamp's email service, Hey.com, has probably noticed the technique they use for lazy-loading their menus.

hey-menu

Basecamp uses details and summary tags in order to achieve a pop-up behavior with native HTML. They use this in conjunction with a fancy Stimulus controller which seems to add a src attribute to the revealed turbo-frame. This loads in the menu asynchronously without having to manually manage AJAX requests.

Thanks to some additions to Turbo during its development, a slightly different approach can be used to achieve a similar result while omitting the complex popup-menu controller.

Although this solution omits the use of Basecamp's popup-menu controller, it still uses the two-part punch of StimulusJS and Turbo.

The first important element of this setup is the use of a toggle controller.

import { Controller } from "stimulus"

export default class extends Controller {
  static targets = [ "toggled" ]
  static classes = [ "toggle" ]

  toggle(event) {
    event.preventDefault()
    // Unblurring focused target if there is one
    if (event.target) {
      document.activeElement.blur()
    }

    this.toggledTargets.forEach(
      (toggled) => toggled.classList.toggle(this.toggleClass)
    )
  }
}

It's worth mentioning that much of this toggle code was lifted from Matt Swanson's excellent article on composing behaviors using StimulusJS. I highly recommend giving it a read if you haven't already.

This controller allows for a style to be toggled on elements when a given action occurs. In this case, it's used to toggle the visibility of our pop-up menu.

<div data-controller="toggle" data-toggle-toggle-class="hidden" class="relative">
  <%= button_to "#", data: { action: "click->toggle#toggle" } do %>
    Invite Member
  <% end %>
  <div data-toggle-target="toggled" class="hidden absolute top-10 right-0">
    <%= turbo_frame_tag "your-popup" do %>
      <div>
        <span>Loading...</span>
      </div>
    <% end %>
  </div>
</div>

The toggle controller is added to the HTML markup of a div containing a turbo-frame. When the button is clicked, the toggle action of the controller is triggered in order to make the div containing the turbo-frame visible.

This is where Turbo comes into play and a feature added to Turbo during its time in beta, lazy-loading based on visibility, can be used. First a controller action should be added that returns a turbo-frame matching the id of the turbo-frame that's in the HTML loaded with the toggle controller.

class ResourceController < ApplicationController
  def new
    @resource = Resource.new
  end
end
<%= # resources/new.html.erb %>
<%= turbo_frame_tag "your-popup" do %>
  <div>
    <%= # Your menu/form/content goes here %>
  </div>
<% end %>

In addition to this, we will have to add the special loading="lazy" attribute as well as a src attribute to the first turbo-frame.

<div data-controller="toggle" data-toggle-toggle-class="hidden" class="relative">
  <%= button_to "#", data: { action: "click->toggle#toggle" } do %>
    Invite Member
  <% end %>
  <div data-toggle-target="toggled" class="hidden absolute top-10 right-0">
    <%= turbo_frame_tag "your-popup", src: new_resource_path, loading: :lazy do %>
      <div>
        <span>Loading...</span>
      </div>
    <% end %>
  </div>
</div>

This ensures that when the pop-up is first toggled open, it will load the turbo-frame rendered by the new action. Every subsequent toggle will just reveal the already loaded pop-up. Without the use of the loading="lazy" attribute, the pop-up would be loaded after the initial page load regardless of its visibility. In that way, the loading="lazy" attribute provides the secret sauce that allows use to circumvent the use of the more-complex controller used by Basecamp in Hey.

Once fully styled, here's how the implementation could look for a form.

hey-style-menu

Let me know if you found this article helpful, and leave any suggestions for improvement below in the comments!


This content originally appeared on DEV Community and was authored by Jacob Daddario


Print Share Comment Cite Upload Translate Updates
APA

Jacob Daddario | Sciencx (2021-07-28T20:35:38+00:00) HEY-style Pop-ups Using Hotwire. Retrieved from https://www.scien.cx/2021/07/28/hey-style-pop-ups-using-hotwire/

MLA
" » HEY-style Pop-ups Using Hotwire." Jacob Daddario | Sciencx - Wednesday July 28, 2021, https://www.scien.cx/2021/07/28/hey-style-pop-ups-using-hotwire/
HARVARD
Jacob Daddario | Sciencx Wednesday July 28, 2021 » HEY-style Pop-ups Using Hotwire., viewed ,<https://www.scien.cx/2021/07/28/hey-style-pop-ups-using-hotwire/>
VANCOUVER
Jacob Daddario | Sciencx - » HEY-style Pop-ups Using Hotwire. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2021/07/28/hey-style-pop-ups-using-hotwire/
CHICAGO
" » HEY-style Pop-ups Using Hotwire." Jacob Daddario | Sciencx - Accessed . https://www.scien.cx/2021/07/28/hey-style-pop-ups-using-hotwire/
IEEE
" » HEY-style Pop-ups Using Hotwire." Jacob Daddario | Sciencx [Online]. Available: https://www.scien.cx/2021/07/28/hey-style-pop-ups-using-hotwire/. [Accessed: ]
rf:citation
» HEY-style Pop-ups Using Hotwire | Jacob Daddario | Sciencx | https://www.scien.cx/2021/07/28/hey-style-pop-ups-using-hotwire/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.