DEV Community

Cover image for Launch a Turbo Modal with URL Params Using Stimulus
Rails Designer
Rails Designer

Posted on • Originally published at railsdesigner.com

Launch a Turbo Modal with URL Params Using Stimulus

This article was originally published on Rails Designer — The First Professionally-Designed UI Components Library for Rails


Having certain screens in a modal (or slide over) on top of your app can be great to give that context the user needs for the action they want to take. Think: settings for a page they are editing, a notifications list or a list of tasks to be done.

This is really easy to create with Rails and Turbo (and even easier with Rails Designer's ModalComponent or SlideOverComponent) 💡). But what if you want to link to that screen from an email or allow your users to share it with their team, like: example.com?v=settings. No problem with a small, single-purpose Stimulus controller!

Yes, the beauty of Turbo Frames is you can link to a standalone page for, say, the settings of a page, but that would remove the context of the page a modal gives. So that is what's on the menu today. Let's get started! 🚀

Another tip: Rails Designer has this controller, along with a complete library of UI components for Rails, for you!

How to Open Turbo Modal Using URL Params and Stimulus

To me the beauty of Stimulus is it allows you to write small, maintainable controllers that are typically concerned with one purpose. That's also the case for this controller.

I assume you have a Rails app ready. I also assume you have a way of showing a modal or slide over through a turbo frame. If not, check this article on how to create a modal with Rails and Hotwire.

Let's create the basics for the Stimulus controller first: bin/rails generate stimulus turbo_frame_load. Then set up some value properties: paramName (defaulting to "v") and the paths. The latter value object is where the mapping between a value and a path is set.

import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  static values = {
    paramName: { type: String, default: "v" },
    paths: Object
  };
}
Enter fullscreen mode Exit fullscreen mode

Then onto the connect function, as the modal/slide over needs to be set every time an URL is loaded.

import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  // …

  connect() {
    this.element.src = this.pathsValue[this.#param];
  }
}
Enter fullscreen mode Exit fullscreen mode

Easy enough! it sets the element's src attribute with the value matching this.#param. Let's create that private function.

import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  // …

  // private

  grails-form-inline-validation.jpget #param() {
    return this.#params.get(this.paramNameValue);
  }

  get #params() {
    return new URLSearchParams(window.location.search);
  }
}
Enter fullscreen mode Exit fullscreen mode

(if you haven't seen the // private line or the # before those function names, go read this article on properly structuring your Stimulus controllers).

get #param() calls get #params() that creates a URLSearchParams object from the query string of the current page's URL, allowing easy access and manipulation of URL parameters.

🧑‍🎨✨ Looking to up your Rails app's UI? Rails Designer can help you. Explore all the options today. ✌️

Now set up the controller to the turbo-frame element:

<%= turbo_frame_tag "modal", data: {controller: "turbo-frame-load", turbo_frame_load_paths_value: {settings: settings_path, notifications: notifications_path}} %>
Enter fullscreen mode Exit fullscreen mode

The important part is the paths value: {settings: settings_path, notifications: notifications_path}. Each key should be unique and its value should be a path that can be loaded in the turbo_frame_tag.

With that line in place, you can load http://localhost:3000?v=settings and the settings are loaded in the modal. Sweet!

But let's make one improvement:

import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  // …

  connect() {
    if (this.#isInvalidParam) { return; }
    // …
  }

  // private

  get #isInvalidParam() {
    return !this.#param && !this.pathsValue[this.#param];
  }

  // …
}
Enter fullscreen mode Exit fullscreen mode

This will check if an expected param is valid ánd if it is present in the paths values object.

And that's all you need to load screens in a modal or slide over upon page load. Not more than 10 lines of JavaScript. Don't you love Stimulus? 😍

Top comments (0)