β οΈ Warning: Under Development - This repository is currently under active development. Use at your own risk for production applications.
Skelayzr your UI β load beautifully, by default.
Skelayzr dynamically wraps any component or DOM element in responsive skeleton loaders. It auto-generates loaders based on the element's structure and layout, providing a smooth and consistent loading experience with elegant, soft colors that blend seamlessly with modern UI designs.
- π― Auto-detect dimensions from live DOM elements with intelligent caching
- π§ Content-aware placeholders (text, image, avatar, button, etc.)
- π¨ Beautiful themes: shimmer, solid, pulse with soft, modern colors
- π¦ Lightweight & modular TypeScript-first architecture
- βΏ Accessible by design (
aria-busy, reduced motion, screen reader support) - β‘ Performance optimized with IntersectionObserver and smart caching
- ποΈ Layout intelligence (CSS Grid, Flexbox, aspect ratio preservation)
- π‘οΈ Graceful degradation and comprehensive error handling
- π§ Full TypeScript support with complete type safety
- π Framework integrations (React hook included, Vue/Angular ready)
npm install skelayzr
# or
yarn add skelayzr
# or
pnpm add skelayzr
# or
bun add skelayzr<div id="profile">
<img src="avatar.jpg" alt="Avatar" />
<h2>Jane Doe</h2>
<p>Senior Frontend Developer</p>
</div>import { skelayzr } from 'skelayzr';
import 'skelayzr/styles';
// Wrap element with skeleton (uses soft, modern colors)
skelayzr('#profile', {
theme: 'shimmer',
loading: true
});
// Toggle loading state with options
skelayzr.setLoading('#profile', false);
// Or with custom delay
skelayzr.setLoading('#profile', true, { delay: 0 });import { useSkelayzr } from 'skelayzr/react';
function Profile({ loading, user }) {
const { ref } = useSkelayzr({ loading, theme: 'shimmer' });
return (
<div ref={ref}>
<img src={user.avatar} alt="Avatar" />
<h2>{user.name}</h2>
<p>{user.bio}</p>
</div>
);
}Main function to wrap an element with a skeleton loader.
import { skelayzr, type SkelayzrOptions } from 'skelayzr';
const options: SkelayzrOptions = {
theme: 'shimmer',
loading: true,
delay: 150
};
const instance = skelayzr('#my-element', options);| Option | Type | Default | Description |
|---|---|---|---|
theme |
'shimmer' | 'solid' | 'pulse' | 'custom' |
'shimmer' |
Skeleton animation theme |
loading |
boolean |
false |
Whether to show skeleton immediately |
delay |
number |
150 |
Delay before showing skeleton (ms) |
cacheStrategy |
'lazy' | 'eager' | 'manual' |
'lazy' |
Skeleton caching strategy |
resizeDebounce |
number |
300 |
Resize event debounce time (ms) |
intersectionThreshold |
number |
0.1 |
Intersection observer threshold |
exclude |
string[] |
[] |
CSS selectors to exclude |
gracefulDegradation |
boolean |
true |
Handle errors gracefully |
debug |
boolean |
false |
Enable debug mode |
onError |
function |
- | Error callback function |
// Set loading state
skelayzr.setLoading(element, true);
// Remove skeleton
skelayzr.unwrap(element);
// Auto-scan elements
skelayzr.scan('.skelayzr-auto');
// Cache management
skelayzr.cache.clear();
skelayzr.cache.getSize();
// Get statistics
const stats = skelayzr.getStats();
// Clean up everything
skelayzr.destroy();Pre-configured options for common UI patterns:
// Card layout preset
skelayzr('#card', skelayzr.presets.card());
// List/feed preset
skelayzr('#list', skelayzr.presets.list());
// Form preset
skelayzr('#form', skelayzr.presets.form());Skelayzr comes with beautiful, soft themes that blend seamlessly with modern UI:
shimmerβ Elegant gradient shimmer animation with soft highlightssolidβ Clean static blocks with gentle colors (#f1f3f4)pulseβ Smooth breathing animationcustomβ Use your own CSS classes
/* Light mode - soft, modern colors */
--skeleton-bg: #f1f3f4;
--skeleton-highlight: rgba(255, 255, 255, 0.6);
/* Dark mode - elegant dark theme */
--skeleton-bg: #e5e7ea;
--skeleton-highlight: rgba(240, 240, 240, 0.15);.skelayzr.my-custom-theme {
--skeleton-bg: #f8fafc;
--skeleton-highlight: rgba(255, 255, 255, 0.8);
background: var(--skeleton-bg);
}skelayzr('#element', { theme: 'my-custom-theme' });import { useSkelayzr } from 'skelayzr/react';
function MyComponent({ isLoading, data }) {
const { ref, setLoading } = useSkelayzr({
loading: isLoading,
theme: 'shimmer',
delay: 200
});
// Programmatically control loading
const handleRefresh = () => {
setLoading(true);
fetchData().finally(() => setLoading(false));
};
return (
<div ref={ref}>
<h1>{data?.title}</h1>
<p>{data?.description}</p>
<button onClick={handleRefresh}>Refresh</button>
</div>
);
}skelayzr('#complex-layout', {
layoutHints: {
preserveGrid: true,
respectFlexGrow: true,
maintainAspectRatio: true,
adaptToContainer: true
}
});skelayzr('#content', {
contentTypes: {
avatar: {
selectors: ['.avatar', '[data-avatar]'],
aspectRatio: 1
},
cardTitle: {
selectors: ['h1', 'h2', '.title'],
lineClamp: 1
},
paragraph: {
selectors: ['p', '.description'],
lineClamp: 3
}
}
});Skelayzr automatically uses IntersectionObserver to only create skeletons for visible elements:
skelayzr('#list-container', {
intersectionThreshold: 0.1, // Trigger when 10% visible
cacheStrategy: 'lazy' // Cache skeletons for better performance
});Skelayzr intelligently caches skeleton DOM elements to boost performance:
// Cache similar skeletons automatically
skelayzr('.card', { loading: true }); // Creates and caches
skelayzr('.card2', { loading: true }); // Reuses cached skeleton!
// Manual cache management
skelayzr.cache.clear(); // Clear all cached skeletons
console.log(`Cache size: ${skelayzr.cache.getSize()}`); // Check cache stats
// Cache strategies
const engine = skelayzr.createEngine({
cacheStrategy: 'eager' // 'lazy' | 'eager' | 'manual'
});Cache Benefits:
- β‘ Faster rendering for similar elements
- π§ Smart reuse based on dimensions + content type + theme
- πΎ Memory efficient with automatic cleanup (max 100 items)
- π Performance tracking via
skelayzr.getStats()
Skelayzr follows accessibility best practices:
- Adds
aria-busy="true"to skeleton elements - Provides
aria-label="Loading content" - Respects
prefers-reduced-motion - Maintains focus management
- Supports high contrast mode
Skelayzr has a comprehensive test suite with 37 passing tests:
# Run all tests
npm test
# Run tests with UI
npm run test:ui
# Run tests with coverage
npm run test:coverage
# Start demo server
npm run demoimport { skelayzr } from 'skelayzr';
import { render, screen } from '@testing-library/react';
test('should show skeleton while loading', () => {
const { container } = render(<MyComponent loading={true} />);
expect(container.querySelector('.skelayzr')).toBeInTheDocument();
expect(screen.getByLabelText('Loading content')).toBeInTheDocument();
});
test('should cache skeleton for performance', () => {
const element = document.createElement('div');
skelayzr(element, { loading: true });
const stats = skelayzr.getStats();
expect(stats.cacheSize).toBeGreaterThan(0);
});- Chrome/Edge 88+
- Firefox 87+
- Safari 14+
- React 16.8+ (for React integration)
We welcome contributions! Please see our Contributing Guide for details.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
MIT Β© arnonsang
- Inspired by modern loading patterns in React, Vue, and Angular ecosystems
- Built with TypeScript for better developer experience
- Designed with accessibility and performance in mind
Try Skelayzr locally:
git clone <repo-url>
cd skelayzr
npm install
npm run build
npm run demoVisit:
http://localhost:8080- Full ES module demohttp://localhost:8080/demo-standalone.html- Standalone demo
Made with β€οΈ using TypeScript β’ π Issues β’ π€ Contributing