htmx-ext-skeleton
Version:
An htmx extension for displaying skeleton screens during AJAX requests
185 lines (138 loc) • 4.77 kB
Markdown
# htmx-ext-skeleton
An htmx extension for displaying skeleton screens during requests.
## Installation
### Via CDN
```html
<script src="https://unpkg.com/htmx.org"></script>
<script src="https://unpkg.com/htmx-ext-skeleton"></script>
```
### Via npm
```bash
npm install htmx-ext-skeleton
```
Then import in your JavaScript:
```javascript
import 'htmx.org';
import 'htmx-ext-skeleton';
```
## Usage
### Basic Usage (Default Skeleton)
1. Define a skeleton template with `id="skeleton"`:
```html
<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>
```
2. Add `hx-ext="skeleton"` to your htmx element:
```html
<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:
```html
<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:
```html
<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`:
```html
<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:
```css
.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