HTMX Loading Indicators
HTMX has an in-built way to display loading content the moment a user submits a request. The term they use for this is hx-indicator
. You can read more about it here.
There are several scenarios where a user can trigger a request: Clicking a Link, Clicking a Button, or Submitting a Form.
Scenario 1: Clicking A Link
The most common way to handle this is to replace your main content container with something that indicates content is loading.
- Add two divs inside your htmx target div (in this case
#main-content
). - Wrap your main content in a
.hidden-while-loading
div, and... - Add your loading content in a
.shown-while-loading
div.
<div id="main-content">
<div class="shown-while-loading">
<div class="shimmer p-5">
<div class="rect"></div>
<div class="rect width-.75"></div>
<div class="rect width-.5"></div>
<div class="rect width-.25"></div>
</div>
</div>
<div class="hidden-while-loading">
<%= yield %>
</div>
</div>
Make sure your htmx request specifies an hx-indicator
<body hx-boost="true" hx-target="#main-content" hx-indicator="#main-content">
That's it. Provided you've loaded the CSS below and the Shimmer CSS, and added your shimmer content, this should work out of the box.
Scenario 2: Clicking A Button
In scenarios where the content of the whole page won't change on click, a full replacement of the main div with a shimmer is overkill. In this case a cleaner UX is to simply show the user a loading spinner inside the button they clicked. This is as simple as
- Add
hx-indicator="this"
to the button itself. This will override thehx-indicator
on any outer elements. - Add a loading spinner inside the link or button, wrapped in a
.shown-while-loading
span. - If there's already another icon on the button, it will look bad alongside the loading spinner. So hide it by wrapping it in
.hidden-while-loading
<a hx-indicator="this" href="/foo" class="flex items-center">
Send Notification
<span class="hidden-while-loading">
<svg class="w-4 h-4"></svg>
</span>
<span class="shown-while-loading">
<svg class="w-4 h-4"></svg>
</span>
</a>
Scenario 3: Submitting A Form
When a user submits a form the cleanest UX we've found is to...
- Show a loading spinner on the submit button to indicate the form is saving.
- Communicate that the form is in an interim state and should not be modified.
This can be achieved by doing the following:
- Add
hx-indicator="this"
to the form. - Add the
.faded-while-loading
class to the form. - Add loading spinner icons inside the submit button.
<form hx-indicator="this" class="faded-while-loading">
<button type="submit">
Save
<span class="hidden-while-loading">
<svg class="w-4 h-4"></svg>
</span>
<span class="shown-while-loading">
<svg class="w-4 h-4"></svg>
</span>
</button>
</form>
The SVG
<svg viewBox="0 0 50 50" class=" htmx-indicator">
<path fill="currentColor" d="M43.935,25.146c0-10.355-8.396-18.75-18.75-18.75c-10.355,0-18.75,8.396-18.75,18.75h4.068 c0-8.115,6.567-14.682,14.682-14.682s14.682,6.567,14.682,14.682H43.935z">
<animateTransform attributeType="xml" attributeName="transform" type="rotate" from="0 25 25" to="360 25 25" dur="1s" repeatCount="indefinite"></animateTransform>
</path>
</svg>
The CSS
.htmx-request .shown-while-loading { display: block; }
.htmx-request .hidden-while-loading { display: none; }
.shown-while-loading { display: none; }
.htmx-request.faded-while-loading, .htmx-request .faded-while-loading { opacity: 0.6 }