Skeleton Loader
Skeleton Loader is a Ruby on Rails gem for creating animated placeholders that enhance loading states. Whether rendered through Rails views or dynamically with JavaScript, these skeletons provide a seamless visual experience while content loads.
⚠ Note: Skeleton Loader is an experimental gem currently in early development, exploring the possibilities in the magical world of Rails gems. While loaders are ideally handled client-side, this gem aims to make it easy to add placeholders directly within the Rails realm.
Table of Contents
- Features
- Installation
- Setup
- Rails Integration
- JavaScript Integration
- Configuration
- Code Quality
- Roadmap
- Contributing
- License
Features
- 🚀 Seamless Rails integration: Enhances loading transitions with minimal setup.
- 🔨 Universal skeletons: Creates loading states in Rails views & JavaScript.
- ⚙️ Consistency: Unified templates & options across both environments.
- ⚡ Lightweight & fast: Designed to be fast and easy to implement with minimal dependencies.
Installation
Add this line to your application’s Gemfile:
gem "skeleton-loader"
Then, run:
bundle install
Requirements
- Ruby 2.5 or higher
- Rails 5.0 or higher
- Asset Pipeline (Required for CSS handling)
Setup
CSS Assets
The gem's CSS is always managed via the Asset Pipeline:
/* app/assets/stylesheets/application.css */
*= require skeleton_loader
JavaScript Assets
Include the JavaScript functionality using Asset Pipeline, Webpack, or Importmap, depending on your setup:
Option 1: Asset Pipeline (Default for Rails 5)
In app/assets/javascripts/application.js, add:
//= require skeleton_loader
Option 2: Webpack (Default for Rails 6)
- Install the package using Yarn:
yarn add "@ersync/skeleton-loader"
import SkeletonLoader from "skeleton-loader"
Option 3: Importmap (Default for Rails 7)
- Pin the package in
config/importmap.rb:
pin "skeleton-loader", to: "skeleton_loader.js"
import SkeletonLoader from "skeleton-loader"
Install Templates
To install predefined templates, run:
rails generate skeleton_loader:add_templates
This adds templates to app/views/skeleton_loader/. Customize them as needed.
To restore defaults later:
rails generate skeleton_loader:reset_templates
Rails Integration
The gem provides a primary view helper, skeleton_loader, which generates a skeleton that is automatically replaced with content once loading completes. You can use it with predefined templates or define your own HTML blocks.
skeleton_loader(
content_id:, # Required. Target element ID for replacement
**, # Optional. Customize the template
&block # Optional. Define custom skeleton HTML (excludes type/options)
)
1. Pre-defined Templates
Specify content_id and, optionally, a template type and customization options.
<%= skeleton_loader(content_id: 'content-element',
type: "card",
count: 5,
scale: 1.2,
animation_type: 'animation-pulse') %>
2. Custom Skeletons with a Block
Define your own HTML structure in a block. Note that type and options are not used.
<%= skeleton_loader(content_id: 'content-element') do %>
<div class="custom-skeleton">
<div class="avatar skeleton-circle"></div>
<div class="text-lines"></div>
</div>
<% end %>
See Configuration for all available options.
JavaScript Integration
Skeleton Loader also provides a JavaScript API to dynamically create skeletons independently of Rails views.
💡 You only need this API if you're loading content asynchronously i.e. AJAX calls. For standard Rails views, use the Rails helper method instead.
1. Basic Setup
First, initialize the SkeletonLoader in your JavaScript:
const skeleton = new SkeletonLoader();
2. Creating Skeletons
There are two methods for creating skeletons using JavaScript:
Using Pre-defined Templates
const loader = skeleton.render({
contentId, // Required. ID of the element to replace with skeleton
...options // Optional. See configuration section for available options
});
Creating Custom Skeletons
const loader = skeleton.renderCustom({
contentId, // Required. ID of the element to replace with skeleton
markup // Required. Custom HTML string for skeleton content
});
3. Managing Loading States
Each skeleton instance (both render() and renderCustom()) returns an object with these methods:
isLoading(): Returns the current loading statereveal(): Removes skeleton and displays content
// Check if still loading
if (loader.isLoading()) {
// Do something while content loads
}
// Remove skeleton and show content
loader.reveal();
Practical Examples
Here's some example showing how to use the skeleton loader with an API call:
async function loadUserProfile(userId) {
// Create skeleton while loading
const loader = skeleton.render({
contentId: 'content-element',
type: 'profile'
});
try {
// Fetch your data
const response = await fetch(`/api/users/${userId}`);
const userData = await response.json();
// Update the DOM with your content
document.getElementById('content-element').innerHTML = createUserProfile(userData);
// Remove the skeleton
loader.reveal();
} catch (error) {
console.error('Failed to load user profile:', error);
loader.reveal(); // Always cleanup the skeleton
}
}
async function loadDashboard() {
// Create multiple skeletons
const loaders = {
profile: skeleton.render({ contentId: 'profile', type: 'profile', scale:1.2, width:250 }),
stats: skeleton.render({ contentId: 'stats', type: 'card', scale:1.3, animationType:"sl-flow" }),
activities: skeleton.render({ contentId: 'activities', type: 'list' })
};
// Load your data
const [profileData, statsData, activitiesData] = await Promise.all([
fetchProfile(),
fetchStats(),
fetchActivities()
]);
// Update content and reveal each section
updateProfile(profileData);
loaders.profile.reveal();
updateStats(statsData);
loaders.stats.reveal();
updateActivities(activitiesData);
loaders.activities.reveal();
}
Configuration
Options
The following options can be passed to both the Rails view helper and JavaScript API. Note that Rails uses snake_case (e.g., animation_type), while JavaScript uses camelCase (e.g., animationType).
| Option | Type | Description | Default | Example |
|---|---|---|---|---|
content_id |
String | Unique identifier for the skeleton loader container | nil |
"content-element" |
type |
String | Predefined template type (e.g., "product", "profile") | "default" |
"product" |
width |
Integer | Base width of a single skeleton item in pixels | Depends on type |
250 |
count |
Integer | Number of skeleton items to render | Depends on type |
6 |
per_row |
Integer | Number of skeleton items displayed per row | Depends on type |
4 |
scale |
Float | Size multiplier for all skeleton item dimensions | 1.0 |
1.2 |
animation_type |
String | Type of loading animation | "sl-gradient" |
"sl-glow" |
Notes:
typedetermines default layout and stylingscaleaffects width and spacing proportionallyanimation_typesupports different loading effect styles
Available Templates
Skeleton Loader comes with several pre-built templates, each with their default configurations:
| Template Type | Default Width | Count | Items Per Row |
|---|---|---|---|
card |
200px | 3 | 3 |
comment |
900px | 2 | 1 |
default |
900px | 1 | 1 |
gallery |
320px | 3 | 3 |
paragraph |
900px | 1 | 1 |
product |
320px | 3 | 3 |
profile |
320px | 3 | 3 |
For an interactive preview of available templates and animations, visit the Live Demo.
Available Animations
Choose from several animation styles to match your design:
sl-gradient(default): Smooth gradient movementsl-shine: Shimmer effectsl-pulse: Fade in/outsl-flow: Continuous flowsl-neon: Subtle glowsl-breathing: Gentle scaling
Application Defaults
To set application-wide defaults, create config/initializers/skeleton_loader.rb:
SkeletonLoader.configure do |config|
# Override default template settings
config.templates[:product] = {
width: 400,
count: 6,
per_row: 3
}
# Global settings
config.scale = 1.0 # Default: 1.0
config.animation_type = "sl-gradient" # Default: "sl-gradient"
end
Advanced Configuration
For applications requiring custom HTML elements or styles:
SkeletonLoader.configure do |config|
config. = [] # Default: []
config.additional_allowed_attributes = {} # Default: {}
config.additional_allowed_css_properties = [] # Default: []
end
Code Quality
Skeleton Loader maintains code quality through:
- RSpec: Comprehensive tests covering core functionality.
- CircleCI: Continuous integration ensures all new changes meet quality standards.
- Rubocop: Consistent linting aligns code with Ruby community conventions.
Roadmap
Here are some features I'd like to add when I have time:
- New Templates & Animations: Expanding template and animation options.
- Turbo & Stimulus Support: Enhancing compatibility with Rails Turbo and StimulusJS.
- Builder Helper for Custom Skeletons:: Introducing a helper to easily create custom skeletons (e.g., circles, rectangles, etc.) with customizable options, simplifying the process of designing custom skeletons.
Suggestions and contributions are welcome!
Contributing
To contribute:
- Fork the repository.
- Create a new feature branch.
- Add tests for new features.
- Commit your changes and submit a pull request.
Please follow the Code of Conduct for all contributions.
License
Skeleton Loader is licensed under the MIT License. See LICENSE for details.