htmx-ext-skeleton
v0.2.0
Published
An htmx extension for displaying skeleton screens during AJAX requests
Maintainers
Readme
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-skeletonThen import in your JavaScript:
import 'htmx.org';
import 'htmx-ext-skeleton';Usage
Basic Usage (Default Skeleton)
- 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>- 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 withid="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-skeletonwith any CSS selector for custom templates - Custom targets: Use
hx-skeleton-targetto 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
When an htmx request starts (
htmx:beforeRequest), the extension:- Saves the original content
- Replaces it with the skeleton template
- Adds a
skeleton-loadingclass
When the response arrives (
htmx:beforeSwap), the extension:- Removes the
skeleton-loadingclass - Allows htmx to swap in the new content
- Removes the
If an error occurs, the extension:
- Restores the original content
- Removes the
skeleton-loadingclass
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-skeletonnow accepts any CSS selector instead of just an ID (defaults to#skeletonfor backward compatibility) - New Feature: Added
hx-skeleton-targetattribute to specify a different target for skeleton display - Enhancement: Improved target resolution - falls back to
hx-target, then htmx default ifhx-skeleton-targetnot 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
