Do not restart CSS animations for identical elements
I've got a spinner, and the section of the page with the spinner is replaced periodically. When this happens, the spinner's CSS animation restarts. I want it to continue for as long as an identical spinner is returned.
Similarly, I'd love to have a CSS animation play (and finish) only when an element is first added to a page. But, every hx-get causes the animation to re-play.
I expected this to work because of the way simple class-based transitions are documented (https://htmx.org/docs/#css_transitions):
When htmx swaps in this new content, it will do so in such a way that the CSS transition will apply to the new content, giving you a nice, smooth transition to the new state.
So, in summary, all you need to do to use CSS transitions for an element is keep its id stable across requests!
So I'm keeping a stable id on my element, but no luck. This is on v2.0.4.
Are you using hx-preserve? Could you share a reproducible example?
I wasn't using hx-preserve, since docs say it:
keep[s] an element unchanged during HTML replacement
I've got something like:
<div id="{uniqueId}">
# Some child elements that do change between requests.
</div>
Just tested, and hx-preserve prevents the updates to child elements too. (So, won't work for my use case.)
Could you share a reproducible example?
I'm new to HTMX, is there a playground where it's easy to create a reproducible example?
Showing some HTML+CSS, with all your hx-attributes and sample responses, as well as a detailed explanation of what you expect vs what's happening should be enough.
Found a playground that can load this JSON file:
Nicer file contents, in case that goes away:
// server.js
on.get("/", (request) => {
return render(request, 'index.html')
})
on.get("/tab1", (request) => {
let context = {
tabContent: "Viewing Tab 1"
}
return render(request, 'tabs.html', context)
})
on.get("/tab2", (request) => {
let context = {
tabContent: "Viewing Tab 2"
}
return render(request, 'tabs.html', context)
})
on.get("/tab3", (request) => {
let context = {
tabContent: "Viewing Tab 3"
}
return render(request, 'tabs.html', context)
})
<!-- index.html -->
<html>
<head>
<script src="https://unpkg.com/htmx.org@<2/dist/htmx.js" defer></script>
</head>
<body>
<p>When the "content" div is first shown,
we want to highlight part of it with an animation.
</p>
<p>However, despite having an ID on the .tab-bar element, its animation
is re-played each time we switch tabs.
</p>
<button hx-target="#content" hx-get="/tab1">Show Tabs</button>
<div id="content"></div>
</body>
<style>
.tab-bar {
animation: 100ms linear 3 blink;
}
@keyframes blink {
from { background-color: rgba(0,0,0,0); }
to { background-color: red; }
}
body {
background-color: white;
}
</style>
</html>
<!-- tabs.html -->
<div class="tabs" hx-target="closest .tabs" hx-swap="outerHtml">
<div class="tab-bar" id="uniqueID">
<!--
Not shown here: updating tab state depending on navigation.
It's why we update the whole .tabs, and not just the tabContent.
-->
<button hx-get="/tab1">Tab 1</button>
<button hx-get="/tab2">Tab 2</button>
<button hx-get="/tab3">Tab 3</button>
</div>
<div>{{ tabContent }}</div>
</div>
FWIW, it seems that this is the case that the Idiomorph extension was designed for:
https://htmx.org/extensions/idiomorph/
Things work as expected when using that plugin. (Though, there were a lot of silent failure modes along the way until I got everything configured properly. 😅)
It might be worth mentioning this plugin in the "CSS Transitions" and/or "Animation Examples" sections. Updates with Idiomorph act a lot more like what I was expecting. 👍