pull hx-classes out to an extension

This commit is contained in:
carson
2020-05-24 17:04:59 -07:00
parent d175606707
commit 860d263d4d
15 changed files with 345 additions and 358 deletions

72
src/ext/class-tools.js Normal file
View File

@@ -0,0 +1,72 @@
(function(){
function splitOnWhitespace(trigger) {
return trigger.split(/\s+/);
}
function parseClassOperation(trimmedValue) {
var split = splitOnWhitespace(trimmedValue);
if (split.length > 1) {
var operation = split[0];
var classDef = split[1].trim();
var cssClass;
var delay;
if (classDef.indexOf(":") > 0) {
var splitCssClass = classDef.split(':');
cssClass = splitCssClass[0];
delay = parseInterval(splitCssClass[1]);
} else {
cssClass = classDef;
delay = 100;
}
return {
operation:operation,
cssClass:cssClass,
delay:delay
}
} else {
return null;
}
}
function processClassList(elt, classList) {
var runs = classList.split("&");
for (var i = 0; i < runs.length; i++) {
var run = runs[i];
var currentRunTime = 0;
var classOperations = run.split(",");
for (var j = 0; j < classOperations.length; j++) {
var value = classOperations[j];
var trimmedValue = value.trim();
var classOperation = parseClassOperation(trimmedValue);
if (classOperation) {
if (classOperation.operation === "toggle") {
setTimeout(function () {
setInterval(function () {
elt.classList[classOperation.operation].call(elt.classList, classOperation.cssClass);
}, classOperation.delay);
}, currentRunTime);
currentRunTime = currentRunTime + classOperation.delay;
} else {
currentRunTime = currentRunTime + classOperation.delay;
setTimeout(function () {
elt.classList[classOperation.operation].call(elt.classList, classOperation.cssClass);
}, currentRunTime);
}
}
}
}
}
htmx.defineExtension('class-tools', {
onEvent: function (name, evt) {
if (name === "processedNode.htmx") {
var elt = evt.detail.elt;
var classList = elt.getAttribute("classes") || elt.getAttribute("data-classes");
if (classList) {
processClassList(elt, classList);
}
}
}
});
})();

View File

@@ -155,10 +155,6 @@ var htmx = htmx || (function () {
return getDocument().body.contains(elt);
}
function concat(arr1, arr2) {
return arr1.concat(arr2);
}
function splitOnWhitespace(trigger) {
return trigger.split(/\s+/);
}
@@ -519,56 +515,6 @@ var htmx = htmx || (function () {
return [{trigger: 'click'}];
}
function parseClassOperation(trimmedValue) {
var split = splitOnWhitespace(trimmedValue);
if (split.length > 1) {
var operation = split[0];
var classDef = split[1].trim();
var cssClass;
var delay;
if (classDef.indexOf(":") > 0) {
var splitCssClass = classDef.split(':');
cssClass = splitCssClass[0];
delay = parseInterval(splitCssClass[1]);
} else {
cssClass = classDef;
delay = 100;
}
return {
operation:operation,
cssClass:cssClass,
delay:delay
}
} else {
return null;
}
}
function processClassList(elt, classList) {
forEach(classList.split("&"), function (run) {
var currentRunTime = 0;
forEach(run.split(","), function(value){
var trimmedValue = value.trim();
var classOperation = parseClassOperation(trimmedValue);
if (classOperation) {
if (classOperation.operation === "toggle") {
setTimeout(function () {
setInterval(function () {
elt.classList[classOperation.operation].call(elt.classList, classOperation.cssClass);
}, classOperation.delay);
}, currentRunTime);
currentRunTime = currentRunTime + classOperation.delay;
} else {
currentRunTime = currentRunTime + classOperation.delay;
setTimeout(function () {
elt.classList[classOperation.operation].call(elt.classList, classOperation.cssClass);
}, currentRunTime);
}
}
});
});
}
function cancelPolling(elt) {
getInternalData(elt).cancelled = true;
}
@@ -776,10 +722,7 @@ var htmx = htmx || (function () {
if (sseSrc) {
initSSESource(elt, sseSrc);
}
var addClass = getAttributeValue(elt, 'hx-classes');
if (addClass) {
processClassList(elt, addClass);
}
triggerEvent(elt, "processedNode.htmx");
}
if (elt.children) { // IE
forEach(elt.children, function(child) { processNode(child) });
@@ -815,17 +758,21 @@ var htmx = htmx || (function () {
triggerEvent(elt, eventName, mergeObjects({isError:true}, detail));
}
function ignoreEventForLogging(eventName) {
return eventName === "processedNode.htmx"
}
function triggerEvent(elt, eventName, detail) {
if (detail == null) {
detail = {};
}
detail["elt"] = elt;
var event = makeEvent(eventName, detail);
if (htmx.logger) {
if (htmx.logger && !ignoreEventForLogging(eventName)) {
htmx.logger(elt, eventName, detail);
if (detail.isError) {
sendError(elt, eventName, detail);
}
}
if (detail.isError) {
sendError(elt, eventName, detail);
}
var eventResult = elt.dispatchEvent(event);
forEach(getExtensions(elt), function (extension) {

View File

@@ -1,4 +1,4 @@
describe("hx-classes attribute", function(){
describe("class-tools extension", function(){
beforeEach(function() {
this.server = makeServer();
clearWorkArea();
@@ -10,7 +10,7 @@ describe("hx-classes attribute", function(){
it('adds classes properly', function(done)
{
var div = make('<div hx-classes="add c1">Click Me!</div>')
var div = make('<div hx-ext="class-tools" classes="add c1">Click Me!</div>')
should.equal(div.classList.length, 0);
setTimeout(function(){
should.equal(div.classList.contains("c1"), true);
@@ -20,7 +20,7 @@ describe("hx-classes attribute", function(){
it('removes classes properly', function(done)
{
var div = make('<div class="foo bar" hx-classes="remove bar">Click Me!</div>')
var div = make('<div class="foo bar" hx-ext="class-tools" classes="remove bar">Click Me!</div>')
should.equal(div.classList.contains("foo"), true);
should.equal(div.classList.contains("bar"), true);
setTimeout(function(){
@@ -32,7 +32,7 @@ describe("hx-classes attribute", function(){
it('adds classes properly w/ data-* prefix', function(done)
{
var div = make('<div data-hx-classes="add c1">Click Me!</div>')
var div = make('<div hx-ext="class-tools" data-classes="add c1">Click Me!</div>')
should.equal(div.classList.length, 0);
setTimeout(function(){
should.equal(div.classList.contains("c1"), true);
@@ -40,5 +40,16 @@ describe("hx-classes attribute", function(){
}, 100);
});
it('extension can be on parent', function(done)
{
var div = make('<div hx-ext="class-tools"><div id="d1" classes="add c1">Click Me!</div></div>')
should.equal(div.classList.length, 0);
setTimeout(function(){
should.equal(div.classList.contains("c1"), false);
should.equal(byId("d1").classList.contains("c1"), true);
done();
}, 100);
});
})

View File

@@ -63,7 +63,6 @@
<!-- attribute tests -->
<script src="attributes/hx-boost.js"></script>
<script src="attributes/hx-classes.js"></script>
<script src="attributes/hx-delete.js"></script>
<script src="attributes/hx-error-url.js"></script>
<script src="attributes/hx-ext.js"></script>
@@ -102,6 +101,9 @@
<script src="../src/ext/path-deps.js"></script>
<script src="ext/path-deps.js"></script>
<script src="../src/ext/class-tools.js"></script>
<script src="ext/class-tools.js"></script>
<!-- events last so they don't screw up other tests -->
<script src="core/events.js"></script>

View File

@@ -1,35 +0,0 @@
---
layout: layout.njk
title: </> htmx - hx-classes
---
## `hx-classes`
The `hx-classes` attribute allows you to specify CSS classes that will be swapped onto the element that
the attribute is on. This allows you to apply [CSS Transitions](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Transitions/Using_CSS_transitions)
to your HTML without resorting to javascript.
A `hx-classes` attribute value consists of "runs", which are separated by an `&` character. All
class operations within a given run will be applied sequentially, with the delay specified.
Within a run, a `,` character separates distinct class operations.
A class operation is an operation name `add`, `remove`, or `toggle`, followed by a CSS class name,
optionally followed by a colon `:` and a time delay.
Here are some examples:
```html
<div hx-classes="add foo"/> <!-- adds the class "foo" after 100ms -->
<div hx-classes="remove bar:1s"/> <!-- removes the class "bar" after 1s -->
<div hx-classes="remove bar:1s, add foo:1s"/> <!-- removes the class "bar" after 1s
then adds the class "foo" 1s after that -->
<div hx-classes="remove bar:1s & add foo:1s"/> <!-- removes the class "bar" and adds
class "foo" after 1s -->
<div hx-classes="toggle foo:1s"/> <!-- toggles the class "foo" every 1s -->
```
### Notes
* `hx-classes` is not inherited
* The default delay if none is specified is 100ms

View File

@@ -21,9 +21,9 @@ title: </> htmx - high power tools for html
* [indicators](#indicators)
* [swapping](#swapping)
* [parameters](#parameters)
* [boosting](#boosting)
* [history](#history)
* [requests & responses](#requests)
* [miscellaneous](#miscellaneous)
* [extensions](#extensions)
* [events & logging](#events)
* [configuring](#config)
@@ -364,6 +364,24 @@ If you wish to filter out some parameters you can use the [hx-params](/attribute
Finally, if you want to programatically modify the parameters, you can use the [configRequest.htmx](/events#configRequest.htmx)
event.
## <a name="boosting"></a>[Boosting](#boosting)
Htmx supports "boosting" regular HTML anchors and forms with the [hx-boost](/attributes/hx-boost) 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
<div hx-boost="true">
<a href="/blog">Blog</a>
</div>
```
The anchor tag in this div will issue an AJAX `GET` request to `/blog` and swap the response into the `body` tag.
This functionality is somewhat similar to [Turbolinks](https://github.com/turbolinks/turbolinks) and allows you to use
htmx for [progressive enhancement](https://en.wikipedia.org/wiki/Progressive_enhancement).
## <a name="history"></a> [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):
@@ -448,46 +466,6 @@ The order of operations in a htmx request are:
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.
## <a name="miscellaneous"></a> [Miscellaneous](#miscellaneous)
In addition to the core AJAX functionality, htmx also has a few other tricks up its sleeve that help you build
nice interfaces without javascript.
### Class Swapping
Htmx supports an attribute, [hx-classes](/attributes/hx-classes) that allows you to add, remove and toggle classes after
a delay. This can be used to create CSS transition effects.
Here are some examples:
```html
<!-- adds the class "foo" after 100ms -->
<div hx-classes="add foo"/>
<!-- removes the class "bar" after 1s -->
<div hx-classes="remove bar:1s"/>
<!-- removes the class "bar" after 1s
then adds the class "foo" 1s after that -->
<div hx-classes="remove bar:1s, add foo:1s"/>
<!-- removes the class "bar" and adds
class "foo" after 1s -->
<div hx-classes="remove bar:1s & add foo:1s"/>
<!-- toggles the class "foo" every 1s -->
<div hx-classes="toggle foo:1s"/>
```
Full documentation is available [on the documentation page.](/attributes/hx-classes)
### Boosting
Htmx supports "boosting" regular HTML anchors and forms with the [hx-boost](/attributes/hx-boost) attribute. This
attribute will convert all anchor tags and forms into AJAX requests that, by default, target the body of the page.
This functionality is somewhat similar to [Turbolinks](https://github.com/turbolinks/turbolinks).
## <a name="extensions"></a> [Extensions](#extensions)
Htmx has an extension mechanism that allows you to customize the libraries' behavior. Extensions [are
@@ -505,14 +483,14 @@ Htmx offers some officially supported extensions that are tested against the htm
| Extension | Description
|-----------|-------------
| [`json-enc`](/official-extensions#json-enc) | use JSON encoding in the body of requests, rather than the default `x-www-form-urlencoded`
| [`morphdom-swap`](/official-extensions#morphdom-swap) | an extension for using the [morphdom](https://github.com/patrick-steele-idem/morphdom) library as the swapping mechanism in htmx.
| [`client-side-templates`](/official-extensions#client-side-templates) | support for client side template processing of JSON responses
| [`debug`](/official-extensions#debug) | an extension for debugging of a particular element using htmx
| [`path-deps`](/official-extensions#path-deps) | an extension for expressing path-based dependencies [similar to intercoolerjs](http://intercoolerjs.org/docs.html#dependencies)
| [`rails-method`](/official-extensions#rails-method) | an extension for including the `_method` parameter that [that rails uses](https://guides.rubyonrails.org/form_helpers.html#how-do-forms-with-patch-put-or-delete-methods-work-questionmark) for non-`POST` or `GET` HTTP methods.
| [`json-enc`](/extensions/json-enc) | use JSON encoding in the body of requests, rather than the default `x-www-form-urlencoded`
| [`morphdom-swap`](/extensions/morphdom-swap) | an extension for using the [morphdom](https://github.com/patrick-steele-idem/morphdom) library as the swapping mechanism in htmx.
| [`client-side-templates`](/extensions/client-side-templates) | support for client side template processing of JSON responses
| [`debug`](/extensions/debug) | an extension for debugging of a particular element using htmx
| [`path-deps`](/extensions/path-deps) | an extension for expressing path-based dependencies [similar to intercoolerjs](http://intercoolerjs.org/docs.html#dependencies)
| [`class-tools`](/extensions/class-tools) | an extension for manipulating timed addition and removal of classes on HTML elements
See the [officially extensions](/official-extensions) page for a complete list.
See the [references page](/reference#extensions) for a complete list.
## <a name="events"></a> [Events & Logging](#events)

View File

@@ -0,0 +1,37 @@
---
layout: layout.njk
title: </> htmx - high power tools for html
---
## The `class-tools` Extension
The `class-tools` extension allows you to specify CSS classes that will be swapped onto or off of the elements by using
a `classes` or `data-classes` attribute. This functionality allows you to apply
[CSS Transitions](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Transitions/Using_CSS_transitions)
to your HTML without resorting to javascript.
A `classes` attribute value consists of "runs", which are separated by an `&` character. All
class operations within a given run will be applied sequentially, with the delay specified.
Within a run, a `,` character separates distinct class operations.
A class operation is an operation name `add`, `remove`, or `toggle`, followed by a CSS class name,
optionally followed by a colon `:` and a time delay.
### Usage
```html
<div hx-ext="class-tools">
<div classes="add foo"/> <!-- adds the class "foo" after 100ms -->
<div class="bar" classes="remove bar:1s"/> <!-- removes the class "bar" after 1s -->
<div class="bar" classes="remove bar:1s, add foo:1s"/> <!-- removes the class "bar" after 1s
then adds the class "foo" 1s after that -->
<div class="bar" classes="remove bar:1s & add foo:1s"/> <!-- removes the class "bar" and adds
class "foo" after 1s -->
<div classes="toggle foo:1s"/> <!-- toggles the class "foo" every 1s -->
</div>
```
### Source
<https://unpkg.com/htmx.org/ext/class-tools.js>

View File

@@ -0,0 +1,46 @@
---
layout: layout.njk
title: </> htmx - high power tools for html
---
## The `client-side-templates` Extension
This extension supports transforming a JSON request response into HTML via a client-side template before it is
swapped into the DOM. Currently three client-side templating engines are supported:
* [mustache](https://github.com/janl/mustache.js)
* [handlebars](https://handlebarsjs.com/)
* [nunjucks](https://mozilla.github.io/nunjucks/)
When you add this extension on an element, any element below it in the DOM can use one of three attributes named
`<template-engine>-temlpate` (e.g. `mustache-template`) with a template ID, and the extension will resolve and render
the template the standard way for that template engine:
* `mustache` - looks a mustache &lt;script> tag up by ID for the template content
* `handlebars` - looks in the `Handlebars.partials` collection fot a template with that name
* `nunjucks` - resolves the template by name via `nunjucks.render(<template-name>)
The AJAX response body will be parsed as JSON and passed into the template rendering.
### Usage
```html
<div hx-ext='client-side-template'>
<button hx-get="/some_json"
mustache-template="my-mustache-template">
Handle with mustache
</button>
<button hx-get="/some_json"
handlebars-template="my-handlebars-template">
Handle with handlebars
</button>
<button hx-get="/some_json"
nunjucks-template="my-nunjucks-template">
Handle with nunjucks
</button>
</div>
```
### Source
<https://unpkg.com/htmx.org/ext/client-side-templates.js>

19
www/extensions/debug.md Normal file
View File

@@ -0,0 +1,19 @@
---
layout: layout.njk
title: </> htmx - high power tools for html
---
## The `debug` Extension
This extension includes log all htmx events for the element it is on, either through the `console.debug` function
or through the `console.log` function with a `DEBUG:` prefix.
### Usage
```html
<button hx-ext="debug">Debug Me...</button>
```
### Source
<https://unpkg.com/htmx.org/ext/debug.js>

View File

@@ -0,0 +1,18 @@
---
layout: layout.njk
title: </> htmx - high power tools for html
---
## The `json-enc` Extension
This extension encodes parameters in JSON format instead of url format.
### Usage
```html
<div hx-post='/test' hx-ext='json-enc'>click me</div>
```
### Source
<https://unpkg.com/htmx.org/ext/json-enc.js>

View File

@@ -0,0 +1,25 @@
---
layout: layout.njk
title: </> htmx - high power tools for html
---
## The `morphdom-swap` Extension
This extension allows you to use the [morphdom](https://github.com/patrick-steele-idem/morphdom) library as the
swapping mechanism in htmx.
#### Usage
```html
<header>
<script src="lib/morphdom-umd.js"></script> <!-- include the morphdom library -->
</header>
<body hx-ext="morphdom-swap">
<button hx-swap="morphdom">This button will be swapped with morphdom!</button>
</body>
```
#### Source
<https://unpkg.com/htmx.org/ext/morphdom-swap.js>

View File

@@ -0,0 +1,44 @@
---
layout: layout.njk
title: </> htmx - high power tools for html
---
## The `path-deps` Extension
This extension supports expressing inter-element dependencies based on paths, inspired by the
[intercooler.js dependencies mechanism.](http://intercoolerjs.org/docs.html#dependencies). When this
extension is installed an element can express a dependency on another path by using the `path-deps` property
and then setting `hx-trigger` to `path-deps`:
```html
<div hx-get="/example"
hx-trigger="path-deps"
path-deps="/foo/bar">...</div>
```
This div will fire a `GET` request to `/example` when any other element issues a mutating request (that is, a non-`GET`
request like a `POST`) to `/foo/bar` or any sub-paths of that path.
You can use a `*` to match any path component:
```html
<div hx-get="/example"
hx-trigger="path-deps"
path-deps="/contacts/*">...</div>
```
#### Usage
```html
<div hx-ext='path-deps'>
<ul hx-get="/list" hx-trigger="path-deps" path-deps="/list">
</ul>
<button hx-post="/list">
Post To List
</button>
</div>
```
#### Source
<https://unpkg.com/htmx.org/ext/path-deps.js>

View File

@@ -0,0 +1,20 @@
---
layout: layout.njk
title: </> htmx - high power tools for html
---
## The `rails-method` Extension
This extension includes the rails `_method` parameter in non-`GET` or `POST` requests.
### Usage
```html
<body hx-ext="rails-method">
...
</body>
```
### Source
<https://unpkg.com/htmx.org/ext/rails-method.js>

View File

@@ -1,207 +0,0 @@
---
layout: layout.njk
title: </> htmx - high power tools for html
---
## Official Extensions
The following extensions are tested against htmx and thus are considered officially supported.
### <a name="debug">[`debug`](#debug)
#### Description
This extension includes log all htmx events for the element it is on with the `"DEBUG:"` prefix.
#### Usage
```html
<button hx-ext="debug">Debug Me...</button>
```
#### Source
```javascript
htmx.defineExtension('debug', {
onEvent : function(name, evt) {
if(console.debug){
console.debug(name, evt);
} else if(console) {
console.log("DEBUG:", name, evt);
} else {
throw "NO CONSOLE SUPPORTED"
}
}
});
```
### <a name="rails-method">[`rails-method`](#rails-method)
#### Description
This extension includes the rails `_method` parameter in non-`GET` or `POST` requests.
#### Usage
```html
<body hx-ext="rails-method">
...
</body>
```
#### Source
```javascript
htmx.defineExtension('rails-method', {
onEvent : function(name, evt) {
if(name === "configRequest.htmx"){
var methodOverride = evt.detail.headers['X-HTTP-Method-Override'];
if(methodOverride){
evt.detail.parameters['_method'] = methodOverride;
}
}
}
});
```
### <a name="morphdom-swap">[`morphdom-swap`](#morphdom-swap)
#### Description
This extension allows you to use the [morphdom](https://github.com/patrick-steele-idem/morphdom) library as the
swapping mechanism in htmx.
#### Usage
```html
<header>
<script src="lib/morphdom-umd.js"></script> <!-- include the morphdom library -->
</header>
<body hx-ext="morphdom-swap">
<button hx-swap="morphdom">This button will be swapped with morphdom!</button>
</body>
```
#### Source
```javascript
htmx.defineExtension('morphdom-swap', {
handleSwap : function(swapStyle, target, fragment, settleInfo) {
if (swapStyle === 'morphdom') {
morphdom(target, fragment.outerHTML);
true; // no settle phase when using morphdom!
}
}
});
```
### <a name="json-enc">[`json-enc`](#json-enc)
#### Description
This extension encodes parameters in JSON format instead of url format.
#### Usage
```html
<div hx-post='/test' hx-ext='json-enc'>click me</div>
```
#### Source
```javascript
htmx.defineExtension('json-enc', {
encodeParameters : function(xhr, parameters, elt) {
xhr.requestHeaders['Content-Type'] = 'application/json';
xhr.overrideMimeType('text/json');
return (JSON.stringify(parameters));
}
});
```
### <a name="client-side-templates">[`client-side-templates`](#client-side-templates)
#### Description
This extension supports transforming a JSON request response into HTML via a client-side template before it is
swapped into the DOM. Currently three client-side templating engines are supported:
* [mustache](https://github.com/janl/mustache.js)
* [handlebars](https://handlebarsjs.com/)
* [nunjucks](https://mozilla.github.io/nunjucks/)
When you add this extension on an element, any element below it in the DOM can use one of three attributes named
`<template-engine>-temlpate` (e.g. `mustache-template`) with a template ID, and the extension will resolve and render
the template the standard way for that template engine:
* `mustache` - looks a mustache &lt;script> tag up by ID for the template content
* `handlebars` - looks in the `Handlebars.partials` collection fot a template with that name
* `nunjucks` - resolves the template by name via `nunjucks.render(<template-name>)
The AJAX response body will be parsed as JSON and passed into the template rendering.
#### Usage
```html
<div hx-ext='client-side-template'>
<button hx-get="/some_json"
mustache-template="my-mustache-template">
Handle with mustache
</button>
<button hx-get="/some_json"
handlebars-template="my-handlebars-template">
Handle with handlebars
</button>
<button hx-get="/some_json"
nunjucks-template="my-nunjucks-template">
Handle with nunjucks
</button>
</div>
```
#### Source
<https://unpkg.com/htmx.org/ext/client-side-templates.js>
### <a name="path-deps">[`path-deps`](#path-deps)
#### Description
This extension supports expressing inter-element dependencies based on paths, inspired by the
[intercooler.js dependencies mechanism.](http://intercoolerjs.org/docs.html#dependencies). When this
extension is installed an element can express a dependency on another path by using the `path-deps` property
and then setting `hx-trigger` to `path-deps`:
```html
<div hx-get="/example"
hx-trigger="path-deps"
path-deps="/foo/bar">...</div>
```
This div will fire a `GET` request to `/example` when any other element issues a mutating request (that is, a non-`GET`
request like a `POST`) to `/foo/bar` or any sub-paths of that path.
You can use a `*` to match any path component:
```html
<div hx-get="/example"
hx-trigger="path-deps"
path-deps="/contacts/*">...</div>
```
#### Usage
```html
<div hx-ext='path-deps'>
<ul hx-get="/list" hx-trigger="path-deps" path-deps="/list">
</ul>
<button hx-post="/list">
Post To List
</button>
</div>
```
#### Source
<https://unpkg.com/htmx.org/ext/path-deps.js>

View File

@@ -8,7 +8,6 @@ title: </> htmx - Attributes
| Attribute | Description |
|-----------|-------------|
| [`hx-boost`](/attributes/hx-boost) | progressively enhances anchors and forms to use AJAX requests
| [`hx-classes`](/attributes/hx-classes) | timed modification of classes on an element
| [`hx-confirm`](/attributes/hx-confirm) | shows a confim() dialog before issuing a request
| [`hx-delete`](/attributes/hx-delete) | issues a `DELETE` to the specified URL
| [`hx-error-url`](/attributes/hx-error-url) | a URL to send client-side errors to
@@ -93,3 +92,14 @@ title: </> htmx - Attributes
| [`sseError.htmx`](/events#sseError.htmx) | triggered when an error occurs with a SSE source
| [`swapError.htmx`](/events#swapError.htmx) | triggered when an error occurs during the swap phase
| [`targetError.htmx`](/events#targetError.htmx) | triggered when an invalid target is specified
## <a name="extensions"></a> [Extensions Reference](#extensions)
| Extension | Description
|-----------|-------------
| [`json-enc`](/extensions/json-enc) | use JSON encoding in the body of requests, rather than the default `x-www-form-urlencoded`
| [`morphdom-swap`](/extensions/morphdom-swap) | an extension for using the [morphdom](https://github.com/patrick-steele-idem/morphdom) library as the swapping mechanism in htmx.
| [`client-side-templates`](/extensions/client-side-templates) | support for client side template processing of JSON responses
| [`debug`](/extensions/debug) | an extension for debugging of a particular element using htmx
| [`path-deps`](/extensions/path-deps) | an extension for expressing path-based dependencies [similar to intercoolerjs](http://intercoolerjs.org/docs.html#dependencies)
| [`class-tools`](/extensions/class-tools) | an extension for manipulating timed addition and removal of classes on HTML elements