hx-trigger~~'s consume modifier~~ has surprising behaviour with forms
E: see below for details, consume is completely orthogonal to the issue (it's rather about hx-trigger's presence alone affecting the two forms differently)
hx-trigger="click consume" seems to prevent the button from triggering its form when its enclosed in that form, but not when it references its form by id. In the following example, "click me 1" does nothing while "click me 2" causes an attempt at form submission:
<html>
<head>
<script src="https://unpkg.com/[email protected]" integrity="sha384-Y7hw+L/jvKeWIRRkqWYfPcvVxHzVzn5REgzbawhxAuQGwX1XWe70vji+VSeHOThJ" crossorigin="anonymous"></script>
</head>
<body>
<form action="http://foo" method="POST"><button hx-trigger="click consume">click me 1</button></form>
<form id="bar" action="http://bar" method="POST"></form><button form="bar" hx-trigger="click consume">click me 2</button>
</body>
</html>
The documentation doesn't explicitly say that such form submissions will be prevented (it only mentions other htmx requests; admittedly it calls out htmx requests on parents), but I'd expect that not to differ between these two setups, given that they're used interchangeably (and ttbomk do not differ in behaviour in HTML at all).
Yeah It is interesting. documentation points out or on elements listening on parents and forms have a browser built in listener on button clicks.
in the first form you have there the button click event is consumed so it will not bubble up to the form and trigger the form submit as this is how buttons in forms trigger things. And because the button has no other hx-attributes htmx has no action to complete itself in this case so does nothing.
In the second situation you have used the form=id attribute on the button which the browser uses to retarget the submit trigger from the button click to the form located somewhere else on the page. So you would expect the htmx consume here would prevent the button click bubbling up to its parent form (but there is none) in this case and its probably working as expected. But the default browser behavior of redirecting events to a remote form will still be in place as htmx doesn't alter default browser functions by design.
If you read the documentation very literally, it only claims that hx-trigger's consume modifier affects other htmx requests, which should not include vanilla HTML form submission. So, regardless of what's the intended behaviour wrt forms here, the documentation doesn't describe the current behaviour accurately.
Yeah after all it all comes down to this about consume:
https://github.com/bigskysoftware/htmx/blob/326ff3b296cf5e3eb0ec7799a9f607818776628c/src/htmx.js#L2439-L2441
The docs could probably be improved to specify that consume will simply call stopPropagation
Though, it should be noted here that it's not consume that prevents your form from submitting, as the event.stopPropagation doc mentions
The stopPropagation() method of the Event interface prevents further propagation of the current event in the capturing and bubbling phases. It does not, however, prevent any default behaviors from occurring; for instance, clicks on links are still processed. If you want to stop those behaviors, see the preventDefault() method.
Using your example above, you can see on this JSFiddle that even without the consume keyword, the form is still prevented from submitting.
The preventDefault call comes from here:
https://github.com/bigskysoftware/htmx/blob/b71af75f1af7d5d3ae562686625fe131f6923e5a/src/htmx.js#L2396-L2398
shouldCancel itself, will return true if the element is a submit button inside a form and the event is a click or a submit
https://github.com/bigskysoftware/htmx/blob/b71af75f1af7d5d3ae562686625fe131f6923e5a/src/htmx.js#L2320-L2322
The idea being that if a button has a hx-trigger attribute defined, it's normally going to make a request (you didn't put any hx-get/post/whatever in your example on the buttons themselves but I assume there would be one of those in a real situation), thus we want to prevent the enclosing form's default submit.
You can see the problematic behavior on this JSFiddle, almost the same example as before, I just added hx-post attributes to the button. See how the second one does 2 requests ; the htmx one + the default submission. We probably don't ever want that to happen.
So I would say this is a bug, we actually didn't have any support for the form attribute a year back (see #1559 #1815), it's very likely to have simply been overlooked (by none other than myself, sigh) at that time.
Maybe it coud simply be fixed by replacing the closest form check in shouldCancel by this one:
https://github.com/bigskysoftware/htmx/blob/b71af75f1af7d5d3ae562686625fe131f6923e5a/src/htmx.js#L2715
So, to sum it up:
-
consumehas actually nothing to do with the issue here, as it stops propagation but does not prevent default - the real issue is that the
formattribute isn't processed at all right now to determine whether we should prevent default submission or not (and in this case, we should)
If you'd like to look into it, feel free to investigate and submit a bugfix PR! And add test cases of course 😁
I think this can be closed now.