DEV Community

Cover image for Hotwire + Tailwind: Spinner without Javascript
Elvinas Predkelis
Elvinas Predkelis

Posted on • Updated on

Hotwire + Tailwind: Spinner without Javascript

This article will outline how to show a spinner while loading a turbo frame without additional Javascript.

Disclaimer - The setup includes Tailwind configuration which is technically Javascript.


Idea and Setup

The setup is pretty straight-forward. It's just a turbo frame with a spinner inside of it.

However, when the frame is being loaded, it looks something like <turbo-frame id="loadable" busy="" aria-busy="true"> - it has a [busy] attribute attached to it.

Turns out, it's possible to leverage that [busy] attribute. πŸ’†


Adding Tailwind modifiers

This is where most of the πŸͺ„πŸŽ© magic 🎩πŸͺ„ happens. Tailwind allows to set up custom modifiers which is exactly what we need in this case.

// tailwind.config.js

let plugin = require("tailwindcss/plugin")
module.exports = {
  // ...
  plugins: [
    plugin(({ addVariant }) => {
      addVariant("busy", "&[busy]")
      addVariant('group-busy', ':merge(.group)[busy] &')
    })
  ]
}
Enter fullscreen mode Exit fullscreen mode

Here a busy modifier is set up which is bound to the [busy] attribute. Also, group-busy is added to target the spinner inside of the parent turbo frame.


Finishing touches

Now we can just ✨sprinkle✨ some classes on some elements.

<turbo-frame id="loadable" class="group">
  <svg
    class="group-busy:inline hidden h-6 w-6 animate-spin"
    xmlns="http://www.w3.org/2000/svg"
    fill="none"
    viewBox="0 0 24 24"
  >
    <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
    <path
      class="opacity-75"
      fill="currentColor"
      d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
    ></path>
  </svg>
</turbo-frame>
Enter fullscreen mode Exit fullscreen mode

In this instance, the spinner just appears while the turbo frame is being loaded. The frame element now has a group class while the spinner now has group-busy:inline hidden classes.

Obviously, you can now style it to your liking when using the respective modifiers. For example, busy:opacity-50 will make the turbo frame transparent while loading.


Wrapping up

The main goal was to once again shake off some unnecessary Javascript from the codebase. This turned out to be a rather tidy way of doing so while keeping the simplicity of Hotwire and the flexibility of Tailwind.


If you have any questions or suggestions, feel free to reach out to me on Twitter or visit my website!

Discussion (0)