Search code examples
htmlhtmx

Swap a form on error, or redirect on success using HTMX


I have a login form marked up like this:

<div id="login_form" hx-ext="response-targets">
    <form action="/login" method="POST" hx-boost="true" hx-target="#login_form" hx-target-400="#login_form" hx-swap="innerHTML">
        ...
        <button type="submit">Log in</button>
    </form>
</div>

When there's an error, backend returns the form with outlined errors, with 400 status code (hence response-targets extension). On success, backend responds HX-Location header of user's profile page, where I expect user to be redirected. Put simply:

  1. Form should be re-rendered on error (400 Bad Request)
  2. User should be redirected to their profile page on success (200 OK)

What actually happens is that HTMX renders entire user's profile page in #login_form instead of redirecting, as if hx-target overrides or takes precedence over HX-Location header.

Tried this without response-target plugin, it works the same. With response-target plugin I can't omit hx-target because then hx-target-400 is not recognized or handled.

How can I put it together so forms are re-rendered on errors, or redirected to a page on success?


Solution

  • Behavior where hx-target is populated with the whole page that I wanted to redirect to happens when both Location and HX-Location headers are present.

    Fix is simple - if backend detects that request is coming from HTMX (by checking if HX-Request request header exists), it responds with HX-Location redirection, and if not it responds with Location header.

    Reason why I was sending both headers is because I started with an idea of progressive enhancement. My assumption was that HTMX (v1.9.6) will use HX-Location when it finds it, with Location left as a fallback for request not coming form HTMX (or with JavaScript disabled).