# Issue with Hotwire, Apline JS and Tailwind

**URL:** https://discuss.hotwired.dev/t/issue-with-hotwire-apline-js-and-tailwind/1852
**Category:** General
**Created:** [January 3, 2021, 8:31pm UTC](https://discuss.hotwired.dev/t/issue-with-hotwire-apline-js-and-tailwind/1852 "2021-01-03T20:31:45Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![BryTai](https://yyz1.discourse-cdn.com/flex027/user_avatar/discuss.hotwired.dev/brytai/32/1313_2.png) [@BryTai](https://discuss.hotwired.dev/u/BryTai)
#### Post date: [January 3, 2021, 8:31pm UTC](https://discuss.hotwired.dev/t/issue-with-hotwire-apline-js-and-tailwind/1852/1 "2021-01-03T20:31:45Z")

</div>

Im trying to identify the issue I’m having and hopefully someone here will be able to shed some light. I’m in the process of implementing Hotwire into an existing app I’m building. I have a admin page that has tabs who’s content is populated via turbo\_frame\_tag.  
My admin.html.erb page lazy loads the first tabs content like so

`<%= turbo_frame_tag "tab_content", src: tab_1_content_path %>`

Within the tab content, I have a modal and a dropdown that Im using tailwind and alpinejs to style, etc.  
The problem I am running into is that when I click a link to navigate to my admin page, The modal and dropdown that are suppose to be hidden by alpinejs are showing and will not function.  
If I refresh the page, they start to preform correctly.

It seems like I’m missing something in regards to the lazy load with the turbo\_frame.  
On a separate page, I am also using turbo\_frame\_tag in the same way except I don’t lazy load the content because I am rendering a partial within my initial turbo\_frame\_tag

```
<%= turbo_frame_tag "tab_content" do %>
  <%= render 'accounts/dashboard', account: @account %>
<% end %>

```

My partial also has a dropdown and a modal within, yet I don’t have the same issue.

Thanks for any suggestions 🙂

---

<div class="post-metadata">

### Author: ![miczed](https://yyz1.discourse-cdn.com/flex027/user_avatar/discuss.hotwired.dev/miczed/32/1445_2.png) [@miczed](https://discuss.hotwired.dev/u/miczed)
#### Post date: [January 14, 2021, 1:07pm UTC](https://discuss.hotwired.dev/t/issue-with-hotwire-apline-js-and-tailwind/1852/2 "2021-01-14T13:07:59Z")

</div>

I had a similar issue and solved it by using the following package:

> **[SimoTod/alpine-turbo-drive-adapter](https://github.com/SimoTod/alpine-turbo-drive-adapter)**
>
> Bridge library to enable full support for Alpine components in pages using Turbolinks

---

<div class="post-metadata">

### Author: ![BryTai](https://yyz1.discourse-cdn.com/flex027/user_avatar/discuss.hotwired.dev/brytai/32/1313_2.png) [@BryTai](https://discuss.hotwired.dev/u/BryTai)
#### Post date: [January 16, 2021, 1:21am UTC](https://discuss.hotwired.dev/t/issue-with-hotwire-apline-js-and-tailwind/1852/3 "2021-01-16T01:21:41Z")

</div>

Thank you, I have been using the similar `alpine-hotwire-turbo-adapter` package. I tried switching to the one you posted, but I’m still having the same problem. The dropdowns etc I have function properly as long as they are not lazy loaded in, via `turbo_frame_tag "tab_content", src: tab_1_content_path`  
I can’t edit my original post, so Ill try and lay out what I have better here.

admin.html.erb

```
<h1>Admin</h1>
<%= turbo_frame_tag "tab_content", src: tab_1_content_path %>

```

tab\_1\_content.html.erb

```
<%= turbo_frame_tag "tab_content" do %>
<div class="dropdown">
  Alpine controlled drop down
</div>

<div class="modal">
  Alpine controlled modal
</div>
<% end %>

```

When navigating to the admin page, the dropdown and modal are shown when they are suppose to be hidden and do not function correctly until I refresh the page. Contrast that to this…

show.html.erb

```
<h1>User</h1>
<%= turbo_frame_tag "tab_content" do %>
  <%= render 'user_content' %>
<% end %>

```

\_user\_content.html.erb

```
<div class="dropdown">
  Alpine controlled drop down
</div>

<div class="modal">
  Alpine controlled modal
</div>

```

This works correctly and has the dropdown and modal hidden and functioning when I navigate to the show page

---

<div class="post-metadata">

### Author: ![ivanprats](https://avatars.discourse-cdn.com/v4/letter/i/f05b48/32.png) [@ivanprats](https://discuss.hotwired.dev/u/ivanprats)
#### Post date: [January 21, 2021, 1:19pm UTC](https://discuss.hotwired.dev/t/issue-with-hotwire-apline-js-and-tailwind/1852/4 "2021-01-21T13:19:47Z")

</div>

I’m experiencing the same issues as well.

After lots of trial and error, the problem seems to be that, when using lazy-loaded frames, Alpine doesn’t initialize the newly rendered components.

**General problem**

The reason is that Alpine needs to run Alpine.initializeComponent(componentDOMElement) in order to activate it. (if you have properly installed it) Alpine already does this to all components that are _initially_ in the document, upon first load of the page.

The problem seems to be that: upon first page load with lazy-loaded turbo-frames, all Alpine sees is:

```html
...
<turbo-frame src="..." id="...">

</turbo-frame>
...

```

The frame hasn’t (yet) loaded the html where your Alpine components are, because they just aren’t present upon first page load.

**Your (@BryTai ) project-specific problem**  
When a user goes to the admin dashboard (admin.html.erb), after the HTML is downloaded and Alpine tries to mount the components, the only thing it sees is something like:

```erb
<h1>Admin</h1>
<turbo-frame id="tab_content" src=" the tab_1_content_path ">
</turbo-frame>

```

(You can verfy this by checking the response to the initial page request)

Alpine can’t mount any component: because there are none in the HTML (yet!).

But because the turbo-frame has a `src`: it inmediately downloads the contents of `tab_1_content.html.erb`. Loading its HTML and showing the broken dropdown and modal.

This translates to “When navigating to the admin page, the dropdown and modal are shown when they are suppose to be hidden and do not function correctly until I refresh the page”.

Now, in contrast, in the user page you _render_ the components upon first page load. So the html received by the browser (and Alpine) upon page load is something like:

```erb
<h1>User</h1>
<div class="dropdown">
  Alpine controlled drop down
</div>

<div class="modal">
  Alpine controlled modal
</div>

```

Alpine is then able to mount the components because they have been rendered.

**Hotfix solution (?)**  
(At least this works for me)  
The basic solution that I have found does the following:

> Upon first page load: set a MutationObserver that will listen to changes inside of all `<turbo-frames>` present in the first page load. When the interior of those turbo-frames (aka: its child-nodes) change: look for all uninitialized Alpine components, and initialize them.

In case it can help you out: my (working) code is the following. This script (that first goes through webpack) is loaded only once in the `<head>`. The thing I like the least is the `setTimeout`, but I’ve checked and without it the code doesn’t work (but might be something specific to my project tho, I suggest you to try it without it).

```javascript
import 'alpine-turbo-drive-adapter'
import Alpine from 'alpinejs'

let turboFramesObserver
document.addEventListener('turbo:load', () => {
  if (turboFramesObserver && turboFramesObserver.disconnect)
    turboFramesObserver.disconnect()
  // The setTimout gives a little bit of time to Vue or other agents to render properly the newly injected HTML
  setTimeout(() => {
    // This has been greatly inspired by https://www.smashingmagazine.com/2019/04/mutationobserver-api-guide/
    turboFramesObserver = new MutationObserver(mutations => {
      for (let mutation of mutations) {
        if (mutation.type === 'childList') {
          Alpine.discoverUninitializedComponents(function(el) {
            Alpine.initializeComponent(el)
          })
        }
      }
    })
    
    // Gets all <turbo-frames> present in the page. Before they lazy-load their content.
    let turboFrames = document.querySelectorAll('turbo-frame')
    for (let turboFrame of turboFrames) {
      // Observes each frame, firing the MutationObserver callback upon any "childList" mutation
      turboFramesObserver.observe(turboFrame, {
        attributes: false,
        childList: true,
      })
    }
  }, 500)
})

```

**Ideal solution**  
In order to avoid the `MutationObserver` object/API, the best (in my humbe opinion) would be if Turbo fires an event called something like `turbo:frame-loaded` every time a frame finishes its rendering after receiving a new request from the server.

I’ve seen this talked in the Github discussions and in a couple of [pull requests](https://github.com/hotwired/turbo/pull/59), so I (really) hope it will be implemented soon.

---

<div class="post-metadata">

### Author: ![BryTai](https://yyz1.discourse-cdn.com/flex027/user_avatar/discuss.hotwired.dev/brytai/32/1313_2.png) [@BryTai](https://discuss.hotwired.dev/u/BryTai)
#### Post date: [January 21, 2021, 8:04pm UTC](https://discuss.hotwired.dev/t/issue-with-hotwire-apline-js-and-tailwind/1852/5 "2021-01-21T20:04:17Z")

</div>

Wow, thank you for your write up!  
I’ll give your solution a try and I agree with your “Ideal Solution” going forward.

---

<div class="post-metadata">

### Author: ![onkara](https://avatars.discourse-cdn.com/v4/letter/o/c67d28/32.png) [@onkara](https://discuss.hotwired.dev/u/onkara)
#### Post date: [July 22, 2022, 3:05am UTC](https://discuss.hotwired.dev/t/issue-with-hotwire-apline-js-and-tailwind/1852/6 "2022-07-22T03:05:12Z")

</div>

Was this issue fixed?
