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
- Quick Start
- Usage
- 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
To install Skeleton Loader, add the following line to your Gemfile:
gem "skeleton-loader"
Then, execute:
bundle install
Requirements
- Ruby 2.5 or higher
- Rails 5.0 or higher
- Asset Pipeline (for CSS handling)
Install Templates
Add predefined templates to your app with:
rails generate skeleton_loader:add_templates
This command will place templates in app/views/skeleton_loader/
, which you can customize as needed.
And in case needed, you can revert to default templates by running:
rails generate skeleton_loader:reset_templates
Quick Start
Quickly integrate Skeleton Loader into your Rails app with these steps:
-
Include Assets
-
Rails 7 (Import Maps):
- In
config/importmap.rb
, add:pin "skeleton-loader", to: "skeleton_loader.js"
- In your JavaScript entry file, add:
import SkeletonLoader from "skeleton-loader"
- In
-
In
app/assets/stylesheets/application.css
, add:*= require skeleton_loader
-
Rails 6 (Webpack):
- Run:
npm install "@ersync/skeleton-loader"
- In your JavaScript entry file, add:
import SkeletonLoader from "skeleton-loader"
- Run:
-
Rails 5 (Asset Pipeline):
- In
app/assets/javascripts/application.js
, add://= require skeleton_loader
- In
app/assets/stylesheets/application.css
, add:*= require skeleton_loader
- In
-
-
Use in Views
Use the
skeleton_loader
helper next to the content that loads slowly. Setcontent_id
to the target element's ID and choose atype
for the skeleton template.Example:
<div id="content-element"> <!-- Content that takes time to load --> </div> <%= skeleton_loader(content_id: 'content-element', type: "card") %>
For more detailed instructions, refer to Usage section.
Usage
The gem provides a primary view helper, skeleton_loader
, which generates a div containing a skeleton next to the targeted content element. This skeleton will be hidden once the content element fully loads, providing a seamless loading experience.
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') %>
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.
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 state -
reveal()
: Removes skeleton and displays content
// Check if still loading
if (loader.isLoading()) {
// Do something while content loads
}
// Remove skeleton and show content
loader.reveal();
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:
-
type
determines default layout and styling -
scale
affects width and spacing proportionally -
animation_type
supports 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 movement -
sl-shine
: Shimmer effect -
sl-pulse
: Fade in/out -
sl-flow
: Continuous flow -
sl-neon
: Subtle glow -
sl-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.additional_allowed_tags = [] # 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.