HTMX Boost issue with Alpine-based Navigation component, solution reinit-Tree Alpine? #4485
Replies: 10 comments 11 replies
-
Do you have a simplified example? Are you swapping the whole body or just part of the page? |
Beta Was this translation helpful? Give feedback.
-
Whole body, that is what hx-boost does, similar to Turbolinks or GitHub pjax. At the moment I don’t have a simple example. The JavaScript re-initialise snippet solves the issue. Is it a good or bad thing that I use destroy and initTree? |
Beta Was this translation helpful? Give feedback.
-
I will try and produce a minimal repo highlighting this issue. I am normally a Rails person, but that is too heavy for this. I will instead use Astro (server-side Node). Stay tuned. |
Beta Was this translation helpful? Give feedback.
-
I have created an Astro project highlighting the interaction I see between HTMX Steps:
Now open up Now add htmx.on("htmx:afterSettle", (event) => {
if (event.detail.boosted) {
Alpine.destroyTree(document.body)
Alpine.initTree(document.body)
}
}) This event handler runs after a HTMX The actual navigation bar code lives in Noting, HTMX boost is intercepting the click event on So the |
Beta Was this translation helpful? Give feedback.
-
I timed events: Alpine.destroyTree(document.body)
Alpine.initTree(document.body) This usually takes about 1-2ms in totality. Alpine.start() And this usually takes 2.5-3ms. So when doing normal page change (not When doing a Also, HTMX Interesting. |
Beta Was this translation helpful? Give feedback.
-
I haven't got to the bottom of the issue but I think it's something HTMX does when it detect the same id, I suspect it kind of reverts the style property added by x-show after the swap. If you remove the id, it works as expected. For example, if you pause the mutation observer before the swap, defferring all the Alpine effect until after the DOM settles, it also works with the ID. htmx.on("htmx:beforeSwap", () => {Alpine.deferMutations()})
htmx.on("htmx:afterSettle", () => {Alpine.flushAndStopDeferringMutations()}) I couldn't find anything in the HTMX documentation about the ID behaviour but that doesn't come from Alpine. |
Beta Was this translation helpful? Give feedback.
-
My interpretation is different. Just speculation on my part, and I could be completely wrong.
When it does the swap that all existing Alpine DOM event listeners are destroyed (because the The new However, re-initialising Alpine via If Again, I am not HTMX or Alpine expert, but above is my interpretation of what I am seeing. |
Beta Was this translation helpful? Give feedback.
-
Just tested, this works well: htmx.on("htmx:beforeSwap", (event) => {
if (
event.detail.target.tagName === "BODY" && event.detail.boosted === true)
) {
Alpine.deferMutations()
}
})
htmx.on("htmx:afterSettle", (event) => {
if (
event.detail.target.tagName === "BODY" && event.detail.boosted === true)
) {
Alpine.flushAndStopDeferringMutations()
}
}) Only do Alpine mutation pauses for So, you believe that is more performant than doing this: htmx.on("htmx:afterSettle", (event) => {
if (
event.detail.target.tagName === "BODY" && event.detail.boosted === true)
) {
Alpine.destroyTree(document.body)
Alpine.initTree(document.body)
}
}) |
Beta Was this translation helpful? Give feedback.
-
I did some crude timings for the Both hover around 1ms combined, but generally it seems
Counter-intuitive. I am inclined to go with |
Beta Was this translation helpful? Give feedback.
-
Thanks @SimoTod, My inclination is that If I remove
If Overall I am pleased where I now am. Whenever a I don't doubt this whole issue likely is to work around HTMX Thank you @SimoTod for your assistance and interest. Hopefully this conversation may be useful to the next person who use Alpine.js with HTMX and then enables |
Beta Was this translation helpful? Give feedback.
-
Hello crew,
I encountered an issue with my mobile navigation menu component (implemented in Alpine.js) automatically being open when navigating from page to page with HTMX Boost.
The component starts like:
Obviously the menu should be closed (the default Alpine state as denoted by
mobileNavOpen
) when navigating to a new page. But instead it automatically is open, that is weird.Take away HTMX Boost, everything works as expected.
Boost is similar to the old Rails Turbolinks, it does AJAX
GET
and<body>
swap such that the navigation feels like an SPA navigation. I am not sure what it does with JS, obviously something that makes this Alpine component fail.I chatted with Claude.ai and we both conclude that it appears to be some sort of Alpine initialisation issue. Adding this code to my top-level application.js file solved the issue:
When HTMX
settling
after aboost
page change reinitialise Alpine manually. This seems to work. I infer this is somewhat similar to starting Alpine from scratch when doing a normal Multi-Page-App browser page change (JS and CSS start from scratch includingAlpine.start()
).Is this bad? Are there better solutions?
Beta Was this translation helpful? Give feedback.
All reactions