1

Turbo Streaming Modals in Ruby on Rails

 6 months ago
source link: https://blog.appsignal.com/2024/03/13/turbo-streaming-modals-in-ruby-on-rails.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

In part one of this series, we used Hotwire's Stimulus and Turbo Frames to present modals in Rails.

Now, we'll dive into another method we can use to present modals: Turbo Streams.

What Are Turbo Streams in Ruby on Rails?

Turbo Streams is a subset of Turbo. It allows us to make fine-grained, targeted updates to a page. By default, it contains seven CRUD actions, but we're free to add more actions within our applications.

Now, we'll create a show_remote_modal action which renders and presents the <dialog> from our previous post.

Creating a Custom Action

Create a folder to place all custom Stream Actions in:

shell
$ mkdir app/javascript/stream_actions $ touch app/javascript/stream_actions/index.js

And a file for the Action:

shell
$ touch app/javascript/stream_actions/show_remote_modal.js

Import the Stream Actions into the application:

javascript
// app/javascript/stream_actions/index.js import "./show_remote_modal";
javascript
// app/javascript/application.js // ... import "stream_actions";

If you're using import maps, you'll need to update the config and restart the server:

# config/importmap.rb # ... pin_all_from "app/javascript/stream_actions", under: "stream_actions"

↓ Article continues below

Left squiggle

Is your app broken or slow? AppSignal lets you know.

Monitoring by AppSignal →
Right squiggle

Change the global remote modal container to an HTML element instead of a Turbo Frame:

<%# app/views/layouts/application.html.erb %> <!DOCTYPE html> <html> <%# ... %> <body> <%= yield %> <remote-modal-container></remote-modal-container> </body> </html>

The custom Stream Action can be implemented as:

javascript
// app/javascript/stream_actions/show_remote_modal.js Turbo.StreamActions.show_remote_modal = function () { const container = document.querySelector("remote-modal-container"); container.replaceChildren(this.templateContent); container.querySelector("dialog").showModal(); };

In the above snippet, this refers to StreamElement, which is the custom element underpinning <turbo-stream>. The templateContent getter is defined by this element.

Using the Action with a Rails Helper

Since this is a custom Action, we'll need to manually create a Rails helper to use it.

shell
$ bin/rails generate helper TurboStreamActions
# app/helpers/turbo_stream_actions.rb module TurboStreamActionsHelper def show_remote_modal(&block) turbo_stream_action_tag( :show_remote_modal, template: @view_context.capture(&block) ) end end Turbo::Streams::TagBuilder.prepend(TurboStreamActionsHelper)

We can now use this helper in our views.

<%# app/views/support/tickets/new.html.erb %> <%= turbo_stream.show_remote_modal do %> <dialog id="contact_form_modal" aria-labelledby="modal_title"> <header> <h2 id="modal_title"> Contact us </h2> <form method="dialog"> <button aria-label="close">X</button> </form> </header> <%= form_with(url: support_tickets_path) do |form| %> <%= form.label :message, "Your message" %> <%= form.text_area :message, autofocus: true %> <%= form.button "Close", value: nil, formmethod: :dialog %> <%= form.button "Send" %> <% end %> </dialog> <% end %>

Remember to remove the data-controller attribute: we don't need it anymore. In fact, we can delete the controller itself.

shell
$ rm app/javascript/controllers/remote_modal_controller.js

We'll also need to change the template's name so it renders as a Turbo Stream.

shell
$ mv \ app/views/support/tickets/new.html.erb \ app/views/support/tickets/new.turbo_stream.erb

Turbo Streams are disabled by default for GET requests, so we'll need to manually enable them for the link:

<%# app/views/support/show.html.erb %> <%# ... %> <%= link_to new_support_ticket_path, data: { turbo_stream: true } do %> Show contact form <% end %> <%# ... %>

Refresh the page and click Show contact form. It should still work as before, but now it's rendered using a custom Stream Action!

Wrapping Up

In this two-part series, we explored three different methods to present modals using Hotwire: Stimulus, Turbo Frames, and Turbo Streams. More importantly, the modals were presented with accessibility as the main consideration.

The web should be usable by everyone and it's important for us, as web developers, to put in the effort to make websites accessible.

Basecamp's accessibility guide is publicly available and a fantastic resource to learn the ropes.

I also recommend checking out the docs for Stimulus and Turbo to familiarise yourself with all their features and the APIs used in this series.

Happy coding!

P.S. If you'd like to read Ruby Magic posts as soon as they get off the press, subscribe to our Ruby Magic newsletter and never miss a single post!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK