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: ```javascript const skeleton = new SkeletonLoader(); ``` ### 2. Creating Skeletons There are two methods for creating skeletons using JavaScript: #### Using Pre-defined Templates ```javascript 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 ```javascript 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 ```javascript // 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: ```javascript 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 } } ``` ```javascript 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 stylingscale
affects width and spacing proportionallyanimation_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 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.