Merge branch 'master' into dev

# Conflicts:
#	www/content/docs.md
This commit is contained in:
Carson Gross 2025-09-07 12:14:25 -06:00
commit ccdce87ec3
20 changed files with 44 additions and 18 deletions

View File

@ -10,7 +10,7 @@ This guide outlines how to test htmx, focusing on running tests headlessly or in
npm install
npm run test
```
During test runs it will auto install playwrite
During test runs it will auto install playwright
## Running All Tests

View File

@ -431,12 +431,12 @@
},
{
"name": "historyCacheHit",
"description": "This event is triggered when a cache hit occurs when restoring history\n\nYou can prevent the history restoration via `preventDefault()` to allow alternative restore handling.\nYou can also override the details of the history restoration request in this event if required\n\n##### Details\n\n* `detail.historyElt` - the history element or body that will get replaced\n* `detail.item.content` - the content of the cache that will be swapped in\n* `detail.item.title` - the page title to update from the cache\n* `detail.path` - the path and query of the page being restored\n* `detial.swapSpec` - the swapSpec to be used containing the defatul swapStyle='innerHTML'\n\n",
"description": "This event is triggered when a cache hit occurs when restoring history\n\nYou can prevent the history restoration via `preventDefault()` to allow alternative restore handling.\nYou can also override the details of the history restoration request in this event if required\n\n##### Details\n\n* `detail.historyElt` - the history element or body that will get replaced\n* `detail.item.content` - the content of the cache that will be swapped in\n* `detail.item.title` - the page title to update from the cache\n* `detail.path` - the path and query of the page being restored\n* `detail.swapSpec` - the swapSpec to be used containing the defatul swapStyle='innerHTML'\n\n",
"doc-url": "https://htmx.org/events/#htmx:historyCacheHit"
},
{
"name": "historyCacheMiss",
"description": "This event is triggered when a cache miss occurs when restoring history\n\nYou can prevent the history restoration via `preventDefault()` to allow alternative restore handling.\nYou can also modify the xhr request or other details before it makes the the request to restore history\n\n##### Details\n\n* `detail.historyElt` - the history element or body that will get replaced\n* `detail.xhr` - the `XMLHttpRequest` that will retrieve the remote content for restoration\n* `detail.path` - the path and query of the page being restored\n* `detial.swapSpec` - the swapSpec to be used containing the defatul swapStyle='innerHTML'\n\n",
"description": "This event is triggered when a cache miss occurs when restoring history\n\nYou can prevent the history restoration via `preventDefault()` to allow alternative restore handling.\nYou can also modify the xhr request or other details before it makes the the request to restore history\n\n##### Details\n\n* `detail.historyElt` - the history element or body that will get replaced\n* `detail.xhr` - the `XMLHttpRequest` that will retrieve the remote content for restoration\n* `detail.path` - the path and query of the page being restored\n* `detail.swapSpec` - the swapSpec to be used containing the defatul swapStyle='innerHTML'\n\n",
"doc-url": "https://htmx.org/events/#htmx:historyCacheMiss"
},
{
@ -446,7 +446,7 @@
},
{
"name": "historyCacheMissLoad",
"description": "This event is triggered when a cache miss occurs and a response has been retrieved successfully from the server\nfor the content to restore\n\nYou can modify the details before it makes the swap to restore the history\n\n##### Details\n\n* `detail.historyElt` - the history element or body that will get replaced\n* `detail.xhr` - the `XMLHttpRequest`\n* `detail.path` - the path and query of the page being restored\n* `detail.response` - the response text that will be swapped in\n* `detial.swapSpec` - the swapSpec to be used containing the defatul swapStyle='innerHTML'\n\n",
"description": "This event is triggered when a cache miss occurs and a response has been retrieved successfully from the server\nfor the content to restore\n\nYou can modify the details before it makes the swap to restore the history\n\n##### Details\n\n* `detail.historyElt` - the history element or body that will get replaced\n* `detail.xhr` - the `XMLHttpRequest`\n* `detail.path` - the path and query of the page being restored\n* `detail.response` - the response text that will be swapped in\n* `detail.swapSpec` - the swapSpec to be used containing the defatul swapStyle='innerHTML'\n\n",
"doc-url": "https://htmx.org/events/#htmx:historyCacheMissLoad"
},
{

View File

@ -349,7 +349,7 @@ describe('hx-swap-oob attribute', function() {
}
it.skip('triggers htmx:oobErrorNoTarget when no targets found', function(done) {
// this test fails right now because when targets not found it returns an empty array which makes it miss the event as it should be if (targets.lenght)
// this test fails right now because when targets not found it returns an empty array which makes it miss the event as it should be if (targets.length)
this.server.respondWith('GET', '/test', "Clicked<div id='nonexistent' hx-swap-oob='true'>Swapped</div>")
var div = make('<div hx-get="/test">click me</div>')

View File

@ -176,6 +176,17 @@ that "If something magically works, then it can also magically break."
Despite this fact, I (Carson) still feel it is useful in many situations, and it is used on the <https://htmx.org>
website.
## Loading htmx asynchronously is unreliable
htmx is designed to be loaded with a standard, blocking `<script>` tag, not one that is a [module](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/script#module) or [deferred](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/script#defer).
Although we make a [best-effort attempt](https://github.com/bigskysoftware/htmx/blob/7ae66f9b33a5d39ad4084b0697ea34a6bf559cda/src/htmx.js#L5039-L5058) to initialize htmx regardless of when in the document lifecycle the script is loaded, there are some use-cases that slip through the cracks, typically ones that involve bundling or AJAX insertion of htmx itself.
Our [past attempts](https://github.com/bigskysoftware/htmx/pull/3365#issuecomment-3065080028) to close this gap have all lead to unacceptable regressions.
Therefore, although htmx can be loaded asynchronously, do so at your own risk.
Keep in mind, also, that if your DOM content loads before htmx does, all the htmx-provided functionality will be nonfunctional until htmx loads.
[Prefetching](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel/prefetch) (or even "regular" fetching) htmx before you need it is one possible way to resolve this problem.
## The JavaScript API Is Not A Focus
htmx is a hypermedia-oriented front end library. This means that htmx enhances HTML via

View File

@ -258,7 +258,7 @@ Thank you to all our generous <a href="https://github.com/sponsors/bigskysoftwar
<div>
<a data-github-account="tracebit-com" href="https://tracebit.com/?utm_source=htmx">
<img class="dark-hidden" alt="Tracebit Cloud Canaries" src="/img/tracebit-logo.png">
<img class="dark-visbile" alt="Tracebit Cloud Canaries" src="/img/tracebit-logo-dark.png">
<img class="dark-visible" alt="Tracebit Cloud Canaries" src="/img/tracebit-logo-dark.png">
</a>
</div>
<div>
@ -334,6 +334,13 @@ Thank you to all our generous <a href="https://github.com/sponsors/bigskysoftwar
<img class="dark-visible" src="/img/edubirdie-dark.png" style="width:100%;max-width:250px">
</a>
</div>
<div></div>
<div>
<a data-github-account="TrackityApp" alt="Trackity server side tracking" href="https://www.trackity.com">
<img class="dark-hidden" src="/img/trackity-light.png" style="width:100%;max-width:250px">
<img class="dark-visible" src="/img/trackity-dark.png" style="width:100%;max-width:250px">
</a>
</div>
</div>
<div style="text-align: center;font-style: italic;margin-top: 26px;">ʕ •ᴥ•ʔ made in montana</div>

View File

@ -1699,6 +1699,8 @@ for exploring this topic.
The assignment and checking of CSRF tokens are typically backend responsibilities, but `htmx` can support returning the CSRF token automatically with every request using the `hx-headers` attribute. The attribute needs to be added to the element issuing the request or one of its ancestor elements. This makes the `html` and `body` elements effective global vehicles for adding the CSRF token to the `HTTP` request header, as illustrated below.
Note: `hx-boost` does not not update the `<html>` or `<body>` tags; if using this feature with `hx-boost`, make sure to include the CSRF token on an element that _will_ get replaced. Many web frameworks support automatically inserting the CSRF token as a hidden input in HTML forms. This is encouraged whenever possible.
```html
<html lang="en" hx-headers='{"X-CSRF-TOKEN": "CSRF_TOKEN_INSERTED_HERE"}'>
:

View File

@ -142,6 +142,7 @@ Here are some known implementations of the fragment concept:
* Go
* [Standard Library (use block actions)](https://pkg.go.dev/text/template) [[demo]](https://gist.github.com/benpate/f92b77ea9b3a8503541eb4b9eb515d8a)
* [templ](https://templ.guide) [[Fragment documentation]](https://templ.guide/syntax-and-usage/fragments) [[repo]](https://github.com/a-h/templ)
* Java
* [Thymeleaf](https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#fragment-specification-syntax)
* [Chill Templates (currently in early alpha)](https://github.com/bigskysoftware/chill/tree/master/chill-script)

View File

@ -275,7 +275,7 @@ You can also override the details of the history restoration request in this eve
* `detail.item.content` - the content of the cache that will be swapped in
* `detail.item.title` - the page title to update from the cache
* `detail.path` - the path and query of the page being restored
* `detial.swapSpec` - the swapSpec to be used containing the defatul swapStyle='innerHTML'
* `detail.swapSpec` - the swapSpec to be used containing the defatul swapStyle='innerHTML'
### Event - `htmx:historyCacheMiss` {#htmx:historyCacheMiss}
@ -289,7 +289,7 @@ You can also modify the xhr request or other details before it makes the the req
* `detail.historyElt` - the history element or body that will get replaced
* `detail.xhr` - the `XMLHttpRequest` that will retrieve the remote content for restoration
* `detail.path` - the path and query of the page being restored
* `detial.swapSpec` - the swapSpec to be used containing the defatul swapStyle='innerHTML'
* `detail.swapSpec` - the swapSpec to be used containing the defatul swapStyle='innerHTML'
### Event - `htmx:historyCacheMissLoadError` {#htmx:historyCacheMissLoadError}
@ -314,7 +314,7 @@ You can modify the details before it makes the swap to restore the history
* `detail.xhr` - the `XMLHttpRequest`
* `detail.path` - the path and query of the page being restored
* `detail.response` - the response text that will be swapped in
* `detial.swapSpec` - the swapSpec to be used containing the defatul swapStyle='innerHTML'
* `detail.swapSpec` - the swapSpec to be used containing the defatul swapStyle='innerHTML'
### Event - `htmx:historyRestore` {#htmx:historyRestore}

View File

@ -34,7 +34,7 @@ The click to edit pattern provides a way to offer inline editing of all or part
<label>Email Address</label>
<input type="email" name="email" value="joe@blow.com">
</div>
<button class="btn">Submit</button>
<button class="btn" type="submit">Submit</button>
<button class="btn" hx-get="/contact/1">Cancel</button>
</form>
```

View File

@ -132,8 +132,6 @@ example.
}
```
<script src="https://cdn.jsdelivr.net/npm/htmx.org"></script>
<script src="https://cdn.jsdelivr.net/npm/hyperscript.org"></script>
<script type="text/javascript">
//=========================================================================

View File

@ -89,7 +89,6 @@ window.document.getElementById("cancelButton").addEventListener("click", functio
@import "https://cdnjs.cloudflare.com/ajax/libs/uikit/3.5.9/css/uikit-core.min.css";
</style>
<script src="https://cdn.jsdelivr.net/npm/hyperscript.org"></script>
<script>
//=========================================================================
// Fake Server Side Code

View File

@ -49,7 +49,6 @@ when the content is swapped into the DOM.
<div id="tab-contents" role="tabpanel" hx-get="/tab1" hx-trigger="load"></div>
<script src="https://cdn.jsdelivr.net/npm/hyperscript.org"></script>
<script>
onGet("/tab1", function() {
return `

View File

@ -116,7 +116,7 @@ htmx extensions are split into two categories:
</tr>
<tr>
<td>{% markdown() %} [restored](https://github.com/bigskysoftware/htmx-extensions/blob/main/src/restored/README.md) {% end %}</td>
<td>{% markdown() %} Triggers an event whenever a back button even is detected while using `hx-boost` {% end %}</td>
<td>{% markdown() %} Triggers an event whenever a back button event is detected while using `hx-boost` {% end %}</td>
</tr>
<tr>
<td>{% markdown() %} [safe-nonce](https://github.com/MichaelWest22/htmx-extensions/blob/main/src/safe-nonce/README.md) {% end %}</td>
@ -149,6 +149,10 @@ htmx extensions are split into two categories:
<td>{% markdown() %} [json-enc-custom](https://github.com/Emtyloc/json-enc-custom/blob/main/README.md) {% end %}</td>
<td>{% markdown() %} This extension works similarly to json-enc but allows for very complex structures, such as embedding JSON objects, lists, or handling indexes, just by using the name attribute. {% end %}</td>
</tr>
<tr>
<td>{% markdown() %} [htmx-json](https://github.com/mariusGundersen/htmx-json) {% end %}</td>
<td>{% markdown() %} Support JSON response by transforming the html directly. This is a slightly different appreach than client-side-templates. {% end %}</td>
</tr>
</tbody>
<tbody>
<tr><th scope="rowgroup" colspan="2">Integrations</th></tr>

View File

@ -138,6 +138,7 @@ These examples may make it a bit easier to get started using htmx with your plat
## Rust
- <https://github.com/paultuckey/example-todo-app-rust-htmx>
- <https://github.com/welshdave/actix-htmx>
## Scala

View File

@ -107,10 +107,14 @@ title = "htmx webring"
<tr><td><a rel="nofollow" target="_blank" href="https://xrss.infogulch.com">XRSS</a></td><td>A simple RSS reader inspired by Google Reader</td></tr>
<tr><td><a rel="nofollow" target="_blank" href="https://openunited.com/">OpenUnited</a></td><td>A Digital Talent match-making platform</td></tr>
<tr><td><a rel="nofollow" target="_blank" href="https://gophemeral.com">Gophemeral</a></td><td>Share secrets securely!</td></tr>
<tr><td><a rel="nofollow" target="_blank" href="https://www.thomasricci.dev">thomasricci.dev</a></td><td>Super fast portfolio website</td></tr>
<tr><td><a rel="nofollow" target="_blank" href="https://signup.casa">Signup Casa</a></td><td>Simple, convenient sign-up forms.</td></tr>
<tr><td><a rel="nofollow" target="_blank" href="https://recipes.musicavis.ca">Recipya</a></td><td>A clean, simple and powerful recipe manager your whole family can enjoy.</td></tr>
<tr><td><a rel="noopener" target="_blank" href="https://statusnook.com">Statusnook</a></td><td>Effortlessly deploy a status page and start monitoring endpoints in minutes.</td></tr>
<tr><td><a rel="noopener" target="_blank" href="https://photoquest.wedding/ ">PhotoQuest</a></td><td>The interactive wedding photo game for unique moments that connect.</td></tr>
<tr><td><a rel="noopener" target="_blank" href="https://todo.dankstuff.net/">DankTodo</a></td><td>The First Ever HTMX C (Ulfius) Todo App in History!</td></tr>
<tr><td><a rel="noopener" target="_blank" href="https://dankmuzikk.com/">DankMuzikk</a></td><td>Create, share and play music playlists with the fully hypermedia music player.</td></tr>
<tr><td><a rel="noopener" target="_blank" href="https://danklyrics.com/">DankLyrics</a></td><td>A lyrics finder API, Website and Go package.</td></tr>
</tbody>
</table>
</div>

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -349,7 +349,7 @@ describe('hx-swap-oob attribute', function() {
}
it.skip('triggers htmx:oobErrorNoTarget when no targets found', function(done) {
// this test fails right now because when targets not found it returns an empty array which makes it miss the event as it should be if (targets.lenght)
// this test fails right now because when targets not found it returns an empty array which makes it miss the event as it should be if (targets.length)
this.server.respondWith('GET', '/test', "Clicked<div id='nonexistent' hx-swap-oob='true'>Swapped</div>")
var div = make('<div hx-get="/test">click me</div>')

View File

@ -402,7 +402,7 @@ tbody > tr > th[scope="rowgroup"] {
padding: 1em;
letter-spacing: .1em;
text-transform: uppercase;
background: white;
background: Canvas;
border: solid;
cursor:pointer;
border-radius: 8px;

View File

@ -51,7 +51,7 @@
<div><a href="/essays/">essays</a></div>
<div hx-disable>
<form action="https://google.com/search" role="search" aria-label="Sitewide">
<input type="hidden" name="q" value="site:htmx.org">
<input type="hidden" name="q" value="+[inurl:https://htmx.org]">
<label>
<span style="display:none;">Search</span>
<input type="text" name="q" placeholder="🔍️" class="search-box">