HTMX with Flask - Fade in and out

HTMX with Flask - Fade in and out

In my previous post I converted my boring commenting feature to use HTMX and make commenting much faster. One thing I didn't like about this was that the comment appeared too fast. I would write a comment, click on "Post" and it would just appear underneath in the comments section as if it was always there. There was nothing to tell the user that posting is taking place or that the comment was actually placed there.

I needed something obvious to indicate that the change is happening.

HTMX animations

Digging through the HTMX documentation, I found that it is capable of doing some animations and for my comments, fade in and out seemed appropriate. Post a comment, it slowly fades in, delete it and it slowly fades out before it disappears. Sounds simple.

I needed to add some CSS classes to my page that would enable these effects. I included a new file htmx.css that had these classes defined:

.fade-me-in.htmx-settling{
    opacity: 0;
  }

.fade-me-in {
    opacity: 1;
    transition: opacity 1s ease-out;
  }

.fade-me-out.htmx-swapping {
    opacity: 0;
    transition: opacity 1s ease-out;
  }

My comment template that's being returned from the post call had these classes:

<div id="comment-{{ comment.id }}" class="box fade-me-in fade-me-out">
...
</div>

Button inside the comment that deletes it which worked fine:

              <button class="delete" 
                hx-delete="{{ url_for('posts.del_comment', post_id=comment.id) }}" 
                hx-confirm="Are you sure you wish to delete this comment?"
                hx-target="#comment-{{ comment.id }}"
                hx-swap="outerHTML swap:1s"></button>

It was the same as before, except I added "swap:1s" to the hx-swap tag to declare the duration of the swap.

And the form that posts the comment that didn't work right for some reason, although again all I've done here was add "settle:1s" to hx-swap tag:

<form hx-post="{{ url_for('posts.add_comment', post_id=post.id) }}" hx-swap="afterbegin settle:1s" hx-target="#comments">
...
</form>

With that, fade out worked just fine, but fade in didn't work at all. When I tried to add fade-me-in class to the #comments div which contains all the comments, the whole thing with all the comments faded out and back in when a new comment was posted which looked just weird.

HTMX team comes to the rescue again

Since I couldn't figure it out after trying a few different permutations of settling and swapping and placing them on different components, I sought help from the experts at the HTMX Discord server. I thought I was probably doing something wrong that should be easy enough to set up properly. However, my problem turned out to be more fundamental.

1cg said:

OK, figured out the problem
the .htmx-settling class is applied to the parent element
so you can't use that to differentiate between the elements in it
so, a few options
the class tools extension would let you remove a class and get that fade in effect on a specific div: htmx.org/extensions/class-tools
or, if you are adventurous, hyperscript could do this very easily:

  <div _="on load transition my opacity to 1">
    ...
  </div>

It was late in the day for me and the problem seemed to be more complicated than I had anticipated, so I decided to sleep and continue working on it the next day. However, when I checked back the next day, I found this little miracle on Discord:

1cg said:

was thinking more about this, and I didn't like that htmx didn't support this use case out of the box, so I've added a new temporary class, htmx-added that you can write your transitions against. The core problem here was that the htmx-settling class was added to the target, rather than the added content, which makes it hard to write a transition only for new stuff. htmx-added makes it easy. Will go out w/ the next release of htmx, 1.6.0, this weekend

Imagine my surprise and joy! Instead of having to learn hyperscript, which I know nothing about, although I keep hearing it's amazing, I just had to wait a couple more days for the release of a new version of HTMX.

And sure enough, HTMX v1.6.0 was out the next day with my htmx-added feature included in it.

All I had left to do was to change my include tag in the head to this:

<script src="https://unpkg.com/htmx.org@1.6.0" integrity="sha384-G4dtlRlMBrk5fEiRXDsLjriPo8Qk5ZeHVVxS8KhX6D7I9XXJlNqbdvRlp9/glk5D" crossorigin="anonymous"></script>

And update the new htmx.css to this:

.fade-me-in.htmx-added {
    opacity: 0;
  }

.fade-me-in {
    opacity: 1;
    transition: opacity 1s ease-out;
  }

.fade-me-out.htmx-swapping {
    opacity: 0;
    transition: opacity 1s ease-out;
  }

And that was it! Now my comments fade in alerting the user that their newly posted comment is indeed being processed and added to the page. And the delete button gently removes them into the void, letting the user say their last goodbyes to the unwanted content.

Photo by Markos Mant on Unsplash