How Emissary Uses HTMX

Emissary uses HTMX to power most of its interactivity. This is a tiny, ~14k Javascript library that uses plain HTML attributes to update the contents of a web page with server-rendered content. This fits perfectly with Emissary’s template model and keeps the web client fast and light. Though HTMX is not absolutely required in an Emissary template, many parts of the server expect HTMX to be included on every page.

This is a brief tour of how Emissary uses HTMX. Please see the https://htmx.org website for more complete documentation.

Single-Page-Applications

HTMX provides the same feature set of a typical “single-page-application” without requiring client-side rendering. Instead, HTML fragments are generated by the Emissary server and returned in response to plain-old GET and POST requests. The HTMX library then uses sophisticated swapping algorithms to insert this content into the current page neatly.

Hypertext As The Engine Of Application State

One concept of the early web (and early REST interfaces) was “hypertext as the engine of application state”, or HATEOAS. This simply means that web clients and servers work together as a single unit, with each request/response containing all of the “state” information necessary to continue processing the application and generate the next request/response pair.

HTMX uses this original REST paradigm to power hypermedia applications. All meaningful changes to the application’s state are sent to the server, which updates the model and renders new HTML. For example, when you add a new link to your profile, each change is sent to the server and a new data grid is returned and swapped into your web page.

These transactions are small enough (and the server is fast enough) that updates feel virtually instantaneous, and are indistinguishable from the far more complicated

How HTMX Powers Emissary

Fast-Swapping Pages

In most instances, when updating a page or navigating to a new stream, it is not necessary to reload the entire web page (and all of its CSS, Javascript, etc). Instead, only the new content needs to be swapped in. This is most common when clicking between different actions (or routes) of a single stream.

To do this, HTMX uses the hx-get attribute. This functions similarly to a regular <a href=""> anchor tag, but performs an AJAX request, not a full page reload.

<a hx-get="/{{.StreamID}}/edit" hx-target="main" hx-swap="outerHTML">Edit</a>

Modals and Tooltips

Emissary uses some HTMX Response Headers to implement modal dialogs and pop-ups. These are already designed and tested in the as-modal and as-tooltip action. As an app creator, you only need to wrap your content using these steps to get rich, usable and accessible elements in your application.

Client-Side Events

Certain action steps use the Hx-Trigger Response Header to send events to the client after a POST request completes. For instance, this is a common pattern within the Emissary application.

Here is an example of a typical “view” template, that is wrapped with an HTMX tag that will reload the page whenever a “refreshPage” event is triggered on the browser window.

<div hx-get="/{{.StreamID}}/view" hx-trigger="refreshPage from:window" hx-swap="outerHTML" hx-push-url="false">
	... page content goes here ...
</div>

Below is a definition for this template. When the user performs the the “edit” action, the server performs its updates then sends a “refresh-page” event back to the web browser in the HTTP response. This triggers the HTMX code above and reloads the new page contents for the user.

{
	actions: {
		view: { ... }
		edit: {
			steps: [
				{ ... edit form here ... }
				
				// update the object in the db
				{do: "save"}
				
				// send an event to the client
				{do: "refresh-page"}
			]
		}
	}
}

Server-Sent Events

HTMX supports Server Sent Events via the server-sent-events extension. This tool allows Emissary to listen for updates from the server – for instance, when a Stream is changed by another process or user – and take actions. The most common action, similar to the example above, is to refresh the page to include the new changes within it.

<div hx-get="/{{.StreamID}}" hx-trigger="sse:{{.StreamID}}, refreshPage from:window"  hx-sse="connect:/{{.StreamID}}/sse">

Hyperscript, too

Hyperscript is a companion library to htmx that handles on-page interactivity. Its concise, English-like syntax makes it easy to read and troubleshoot. Hyperscript is included in the default theme, and many templates expect it to be present. However, if needed, it would be very easy to define new themes or templates that do not use Hyperscript.