The head-support extension adds support for head tags in responses to htmx requests.
htmx began as a library focused on partial replacement of HTML within the body tag. The hx-boost attribute moved htmx closer to full HTML-document support, and support for extracting the title tag was eventually added, but full head tag support has never been a feature of the core library. This extension addresses that.
Installing
<script src="https://cdn.jsdelivr.net/npm/htmx.org@next/dist/htmx.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/htmx.org@next/dist/ext/hx-head.js"></script>
Usage
All responses that htmx receives that contain a head tag in them (even if they are not complete HTML documents with a root <html> element) will be processed.
How the head tag is handled depends on the type of htmx request.
If the htmx request is from a boosted element, then the following merge algorithm is used:
- Elements that exist in the current head as exact textual matches will be left in place
- Elements that do not exist in the current head will be added at the end of the head tag
- Elements that exist in the current head, but not in the new head will be removed from the head
If the htmx request is from a non-boosted element, then all content will be appended to the existing head element.
If you wish to override this behavior in either case, you can place the hx-head attribute on the new <head> tag, with either of the following two values:
merge- follow the merging algorithm outlined aboveappend- append the elements to the existing head
Controlling Merge Behavior
You may also control merging behavior of individual elements:
- If you place
hx-head="re-eval"on a head element, it will be re-added (removed and appended) to the head tag on every request, even if it already exists. This can be useful to execute a script on every htmx request, for example. - If you place
hx-preserve="true"on an element, it will never be removed from the head.
Example
Consider the following head tag in an existing document:
<head> <link rel="stylesheet" href="https://the.missing.style"> <link rel="stylesheet" href="/css/site1.css"> <script src="/js/script1.js"></script> <script src="/js/script2.js"></script> </head>
If htmx receives a request containing this new head tag:
<head> <link rel="stylesheet" href="https://the.missing.style"> <link rel="stylesheet" href="/css/site2.css"> <script src="/js/script2.js"></script> <script src="/js/script3.js"></script> </head>
Then the following operations will occur:
<link rel="stylesheet" href="https://the.missing.style">will be left alone<link rel="stylesheet" href="/css/site1.css">will be removed from the head<link rel="stylesheet" href="/css/site2.css">will be added to the head<script src="/js/script1.js"></script>will be removed from the head<script src="/js/script2.js"></script>will be left alone<script src="/js/script3.js"></script>will be added to the head
Events
htmx:removingHeadElement- triggered when a head element is about to be removed. The element is available inevent.detail.headElement. CallpreventDefault()to keep it.htmx:addingHeadElement- triggered when a head element is about to be added. The element is available inevent.detail.headElement. CallpreventDefault()to skip it.htmx:afterHeadMerge- triggered after a head tag merge has occurred, withdetail.added,detail.kept, anddetail.removedarrays.htmx:beforeHeadMerge- triggered before a head merge occurs.