Skip to content

jskopek/htmx-ext-skeleton

Repository files navigation

htmx-ext-skeleton

An htmx extension for displaying skeleton screens during requests.

Installation

Via CDN

<script src="https://unpkg.com/htmx.org"></script>
<script src="https://unpkg.com/htmx-ext-skeleton"></script> 

Via npm

npm install htmx-ext-skeleton

Then import in your JavaScript:

import 'htmx.org';
import 'htmx-ext-skeleton';

Usage

Basic Usage (Default Skeleton)

  1. Define a skeleton template with id="skeleton":
<script type="text/template" id="skeleton">
  <div class="skeleton-placeholder">
    <div class="skeleton-line"></div>
    <div class="skeleton-line"></div>
    <div class="skeleton-line"></div>
  </div>
</script>
  1. Add hx-ext="skeleton" to your htmx element:
<div hx-ext="skeleton" hx-get="/api/data" hx-target="#content">
  Load Data
</div>

<div id="content">
  <!-- Initial content here -->
</div>

Custom Skeleton (Optional)

If you need multiple different skeletons, specify a custom template using any CSS selector:

<script type="text/template" id="custom-skeleton">
  <div class="custom-loading">...</div>
</script>

<div hx-ext="skeleton"
     hx-get="/api/data"
     hx-target="#content"
     hx-skeleton="#custom-skeleton">
  Load Data
</div>

Custom Skeleton Target (Optional)

Use hx-skeleton-target to display the skeleton in a different element than the swap target:

<button hx-ext="skeleton"
        hx-get="/api/data"
        hx-target="#results"
        hx-skeleton-target="#loading-area">
  Load Data
</button>

<div id="loading-area">
  <!-- Skeleton appears here -->
</div>

<div id="results">
  <!-- Data swaps here -->
</div>

If hx-skeleton-target is not specified, the extension falls back to hx-target, and if that's not present, it uses htmx's default target (the element itself).

Alpine.js Integration (Optional)

If Alpine.js is detected, you can override and extend data in your skeleton template using hx-skeleton-alpine:

<script type="text/template" id="skeleton">
  <div x-data="{ title: 'Loading...', count: 3 }">
    <h3 x-text="title"></h3>
    <template x-for="i in count" :key="i">
      <div class="skeleton-item"></div>
    </template>
  </div>
</script>

<div hx-ext="skeleton"
     hx-get="/api/data"
     hx-target="#content"
     hx-skeleton-alpine='{"title": "Loading Projects", "count": 5}'>
  Load Data
</div>

Features

  • Zero configuration: Just add hx-ext="skeleton" and create a template with id="skeleton"
  • Instant feedback: Shows skeleton immediately when request starts
  • Automatic cleanup: Removes skeleton when new content arrives
  • Error handling: Restores original content if request fails
  • History support: Properly handles browser back/forward navigation
  • Multiple skeletons: Use hx-skeleton with any CSS selector for custom templates
  • Custom targets: Use hx-skeleton-target to display skeleton in a different element than the swap target
  • Alpine.js support: Optional integration with Alpine.js for dynamic skeleton templates

How it works

  1. When an htmx request starts (htmx:beforeRequest), the extension:

    • Saves the original content
    • Replaces it with the skeleton template
    • Adds a skeleton-loading class
  2. When the response arrives (htmx:beforeSwap), the extension:

    • Removes the skeleton-loading class
    • Allows htmx to swap in the new content
  3. If an error occurs, the extension:

    • Restores the original content
    • Removes the skeleton-loading class

Styling

Add CSS to style your skeleton screens:

.skeleton-loading {
  pointer-events: none;
  opacity: 0.7;
}

.skeleton-line {
  height: 1rem;
  background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
  background-size: 200% 100%;
  animation: skeleton-loading 1.5s ease-in-out infinite;
  margin-bottom: 0.5rem;
  border-radius: 4px;
}

@keyframes skeleton-loading {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

Changelog

0.2.0 (2025-10-04)

  • Breaking/Enhancement: hx-skeleton now accepts any CSS selector instead of just an ID (defaults to #skeleton for backward compatibility)
  • New Feature: Added hx-skeleton-target attribute to specify a different target for skeleton display
  • Enhancement: Improved target resolution - falls back to hx-target, then htmx default if hx-skeleton-target not specified

0.1.1

  • Fixed issue that could cause skeleton to re-appear when navigating back in browser
  • Added tests
  • Updated Alpine.js integration to require x-data initialization within skeleton template
  • Added optional Alpine.js support to skeleton templates

License

MIT

About

An htmx extension for displaying skeleton screens during requests

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors