Htmx continuously saving

in this article, I will describe how to use HTMX to continuously save form data while filling out the form. Setting up this behavior is quite simple, but there are some pitfalls that should be considered; otherwise, the user experience might not be as good as you would like it to be.

In this Example we use Django as a Backend, but any Backend which gives could deal with Form Data and gets back Html could be used.
Consider we have a simple Html Form which Source Code looks like this:

<form action="" method="post"><br>
  <input type="text" name="name">
  <input type="date" name="birthday">
  <select name="auswahl" required="">
    <option value="option1">Option 1</option>
    <option value="option2">Option 2</option>
  </select>
  <input type="submit" value="Absenden">
</form>

Now to set up htmx and continuously saving you need only to modify the form tag where hx-post sets up htmx und hx-trigger sets up continuously saving:

<form hx-post="{{server}}/user" hx-trigger="change" action="#" hx-swap="outerHTML" method="post">

now you only need an endpoint which processes and saves the form data and gives back partial html:

def create_vorgang(request):
    if request.method == "POST":
        form = VorgangForm(request.POST)
        form.save()    
    return render( request, "partial.html", {"form": form })

So you might be already up an running, but you might want to check if change is a good hx-trigger, as when filling out the birthday field the trigger fires for every part of the date and when
it gets updated (some ms later) the focus swinches back to the day part of the date.
so you might choose to switch to focusout as a trigger. But that still comes with some downfall as when you switch to an select field now it imedatly closes as the state gets not preserved when htmx updates the whole form.

probably the easiest way is to change the shortcomings is by using the idomorph plugin from htmx together with focusout:

<form hx-post="{{server}}/user" hx-trigger="focusout" action="#" hx-swap="morph:outerHTML" method="post">

This way, htmx tries to change only parts of the form which actually changed. And as you use focusout you are normally not in the Area of the Change anymore when the swap happens, so the state of the Form field you are on right now might get preserved

As this probably works in a lot of cases, sometimes you might need more control over how things behave.
Then you need to switch away from only edit the Form Tag. You might instead edit every input tag separately:

<form action="" method="post"><br>
  <input id="name" type="text" name="name" hx-post="{{server}}/user" hx-trigger="focusout">
...

Bear in mind that when you use a non-GET request, the values of all the inputs of the nearest enclosing form will be included.
So you still can use the same Endpoint to save the target. But it has the advantage that you can control which trigger to use for which Field.
In our case, the even bigger advantage is to use hx-select. This will allow you to use only a part of the returned data. So in our example we want to only use #name and then swap only the #name part as well:

<form action="" method="post"><br>
  <input id="name" type="text" name="name" hx-post="{{server}}/user" hx-trigger="focusout" hx-select="#name" hx-swap="outerHTML">
...

Thats it. Enjoy!