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:
- Form should be re-rendered on error (400 Bad Request)
- 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?
2
Answers
Behavior where
hx-target
is populated with the whole page that I wanted to redirect to happens when bothLocation
andHX-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 withHX-Location
redirection, and if not it responds withLocation
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, withLocation
left as a fallback for request not coming form HTMX (or with JavaScript disabled).The problem seems to be that the
hx-target
attribute is taking precedence over theHX-Location
header. Thehx-target
attribute instructs HTMX where to place the response, whileHX-Location
header from the server suggests a redirect.For testing, try and use a small piece of JavaScript with HTMX to handle the redirection based on the
HX-Location
header, overriding the default behavior of HTMX in this scenario.Add an
hx-trigger
attribute to your form to specify a custom JavaScript function that will handle thehtmx:afterOnLoad
event, which fires after HTMX processes a response:Define the
handleResponse
function in your JavaScript code. That function will check for theHX-Location
header in the HTMX response and perform a redirection if it is present:If the server responds with a
HX-Location
header, thehandleResponse
function will catch it and redirect the user to the specified URL, overriding the default behavior of HTMX in this scenario.On the other hand, if the server responds with a 400 status code, the
hx-target-400
attribute will still work as intended, and HTMX will re-render the form with the outlined errors.