Hotwire + Tailwind: Spinner without Javascript | Primevise

[Primevise Homepage](https://primevise.com/)

[Services](https://primevise.com/services) [Work](https://primevise.com/cases) [Products](https://primevise.com/products) [About](https://primevise.com/about) [Blog](https://primevise.com/blog)

[Book an intro call](https://primevise.com/contact)

# Hotwire + Tailwind: Spinner without Javascript

by Elvinas Predkelis

May 22, 2022

### 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] &");
    }),
  ],
};
```

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>
```

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.

Let's talk

## For new products, existing codebases, and ideas that aren't scoped yet.

[Book an intro call](https://cal.com/elvinas/primevise-exploration) [Tell us about your project](https://primevise.com/contact)

© 2026 Primevise. All rights reserved.

- [Services](https://primevise.com/services)
- [Work](https://primevise.com/cases)
- [Products](https://primevise.com/products)
- [About](https://primevise.com/about)
- [Blog](https://primevise.com/blog)
- [Contact](https://primevise.com/contact)

- [Go to Primevise LinkedIn page](https://www.linkedin.com/company/primevise)
- [Go to Primevise X profile](https://x.com/primevisehq)
- [Go to Primevise GitHub organization](https://github.com/primevise)