htmx icon indicating copy to clipboard operation
htmx copied to clipboard

HTMX 2.0: Inline JS in swapped fragments no longer works reliably and CSP prevents hx-on

Open hcstubbe opened this issue 4 months ago • 2 comments

When I swap an HTMX fragment, I sometimes want to run JavaScript in that fragment immediately and only there. This is great for keeping the JavaScript local to the fragment and ensures it is removed when the fragment is destroyed or reloaded. Since HTMX 2.0, this no longer works . I have to use htmx:load or a similar event. I cannot use hx-on because of a very strict Content Security Policy (CSP).

How can I fix this without a hacky solution or excess use of global event listeners?

my.html:

<div id="fragment">
  <p>Hello from fragment</p>
  <script src="my_server/js/my.js"></script>
</div>

my.js:

console.log("Fragment JS executed");

Thank you!

hcstubbe avatar Aug 26 '25 03:08 hcstubbe

I don't think there are any changes in htmx 2.0 that would change the behaviour around script execution. There is a config item allowScriptTags which would need to be left enabled which I think is the default. Any script tags swapped in should just get executed.

Linking to scripts like this is a bit of a hacky way around the issue and may not be ideal. I think the cleanest way to implement this pattern in htmx is to use the hx-trigger response header. With this header you can optionally return this header in some htmx partial page responses that swap content in as normal but then also include an event to trigger with an optional bit of json message data for the custom event to process. You can then setup simple stable body event listeners in an external js file you include in the head of all full responses and this keeps all custom callable javascript well contained and they only trigger and run on request and you avoid issues with page and history back navigations re-running script tags on the page.

Another solution is to use the safe-nonce htmx extension https://htmx.org/extensions/ that can allow inline script tags to be safely run with a strict CSP policy via using proper nonces from server responses.

MichaelWest22 avatar Aug 27 '25 13:08 MichaelWest22

The js script executes after swap. But if it interacts with the swapped fragment, this might not work.

Example: I use quill.js in a project. If I swap the editor including the initiation script in the swapped fragment, the quill.js-editor is not correctly initialized in ~50% of the swaps. This occurs since htmx 2.0.x. I made it work again by moving the initiation script into an event listener outside of the fragment using htmx:load.

This behavior is new and I did not find any reference in the release notes.

hcstubbe avatar Aug 28 '25 00:08 hcstubbe