htmx icon indicating copy to clipboard operation
htmx copied to clipboard

Do not restart CSS animations for identical elements

Open Secret-chest opened this issue 1 year ago • 6 comments

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.

Secret-chest avatar Jun 06 '24 07:06 Secret-chest

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.

NfNitLoop avatar Feb 09 '25 01:02 NfNitLoop

Are you using hx-preserve? Could you share a reproducible example?

geoffrey-eisenbarth avatar Feb 09 '25 01:02 geoffrey-eisenbarth

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?

NfNitLoop avatar Feb 09 '25 01:02 NfNitLoop

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.

geoffrey-eisenbarth avatar Feb 09 '25 02:02 geoffrey-eisenbarth

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>

NfNitLoop avatar Feb 09 '25 02:02 NfNitLoop

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. 👍

NfNitLoop avatar Feb 10 '25 18:02 NfNitLoop