Beyond hx-indicator: Alternative Approaches for htmx Loading Indicators


Purpose

  • hx-indicator tells htmx which element to target for displaying a loading indicator while data is being fetched from the server.

How it works

  1. You add the hx-indicator attribute to an element in your HTML.
  2. This element acts as a reference for htmx.
  3. When an element with hx-indicator is involved in an htmx request (like clicking a button with hx-get):
    • The specified element gets a CSS class htmx-request added to it.

Benefits

  • This htmx-request class allows you to style the indicator element using CSS. You can use this class to show spinners, progress bars, or any visual cue that informs the user about the ongoing request.

Example

<button hx-get="/data" hx-indicator="#loading-indicator">Get Data</button>

<div id="loading-indicator">Loading...</div>

In this example:

  • You can style this class in your CSS to display a "Loading..." message or any preferred indicator.
  • During the request, the element with id="loading-indicator" will have the htmx-request class added.
  • Clicking the button triggers an hx-get request.
  • You need to use CSS to style the htmx-request class for the visual effect.
  • hx-indicator doesn't handle the indicator itself, it just tells htmx which element to target for adding the htmx-request class.


Basic Loading Indicator

<button hx-get="/data" hx-indicator="#spinner">Get Data</button>

<img id="spinner" class="htmx-indicator" src="/img/loading.gif" alt="Loading..." style="display: none;">

This example:

  • When the button is clicked, the htmx-request class is added, likely overriding the display property in your CSS to show the spinner.
  • The CSS display: none; hides the image initially.
  • The hx-indicator points to the #spinner element.
  • Uses an <img> tag with a pre-defined loading GIF as the indicator.

Multiple Indicators on a Page

<div id="content">
  <button hx-get="/data1" hx-indicator=".content-indicator">Load Data 1</button>
  <button hx-get="/data2" hx-indicator=".content-indicator">Load Data 2</button>
</div>

<div class="content-indicator htmx-indicator" style="display: none;">Loading...</div>
  • This ensures only one indicator is shown at a time, regardless of which button is clicked.
  • The hx-indicator on each button targets the same class.
  • Uses a single indicator element with class content-indicator for both buttons.
<a hx-get="/data" hx-indicator="span">Loading data... <span class="htmx-indicator"></span></a>
  • When the request starts, the htmx-request class is added, likely affecting styles of both <span> elements.
  • The second <span> with class htmx-indicator displays the hourglass symbol (assuming you have a font with that character).
  • The first <span> shows the text "Loading data..."
  • hx-indicator is set to "span" to target any child <span> element within the <a> tag.
  • Uses an inline indicator with text.


Manual CSS Classes

  • Use JavaScript to toggle the loading class based on the request lifecycle (started/finished).
  • Add a class like loading to the element that needs the indicator.
  • Instead of relying on hx-indicator, you can directly manage the loading indicator with CSS classes.

Example

<button id="my-button" hx-get="/data">Get Data</button>

<script>
  document.getElementById('my-button').addEventListener('hx:request', () => {
    document.getElementById('my-button').classList.add('loading');
  });

  document.getElementById('my-button').addEventListener('hx:response', () => {
    document.getElementById('my-button').classList.remove('loading');
  });
</script>

<style>
  .loading {
    /* Add styles for loading indicator (e.g., opacity, spinner) */
  }
</style>

Third-party Libraries

  • These libraries offer various animations and customization options.
  • Several JavaScript libraries specialize in creating loading indicators.

Server-side Rendering

  • This approach eliminates the need for client-side manipulation.
  • If your server-side framework supports it, you can render the loading indicator directly in the initial HTML response.
  • For server-side rendering capabilities in your framework, explore that option.
  • If you want pre-built animations and customization, consider third-party libraries.
  • If you need a simple solution and have basic CSS skills, manual CSS classes might be sufficient.