react-content-loader is a SVG-powered library for creating placeholder loading animations (skeleton loaders) in React applications. It provides a flexible way to create Facebook-style loading placeholders that match your content structure, improving perceived performance and user experience. This guide walks through advanced usage of react-content-loader with React, including custom loaders, pre-defined patterns, and complex skeleton structures. This is part 54 of a series on using react-content-loader with React.
Prerequisites
Before you begin, make sure you have:
- Node.js version 14.0 or higher installed
- npm, yarn, or pnpm package manager
- A React project (version 16.8 or higher) or create-react-app setup
- Basic knowledge of React hooks (useState, useEffect)
- Familiarity with SVG and CSS
- Understanding of async operations and loading states
Installation
Install react-content-loader using your preferred package manager:
npm install react-content-loader
Or with yarn:
yarn add react-content-loader
Or with pnpm:
pnpm add react-content-loader
After installation, your package.json should include:
{
"dependencies": {
"react-content-loader": "^7.0.0",
"react": "^18.0.0",
"react-dom": "^18.0.0"
}
}
Project Setup
react-content-loader requires no additional setup. Import the components and you're ready to use them.
First Example / Basic Usage
Let's create a simple skeleton loader. Create a new file src/ContentLoaderExample.jsx:
// src/ContentLoaderExample.jsx
import React, { useState, useEffect } from 'react';
import ContentLoader from 'react-content-loader';
function ContentLoaderExample() {
const [isLoading, setIsLoading] = useState(true);
const [data, setData] = useState(null);
useEffect(() => {
// Simulate API call
setTimeout(() => {
setData({ title: 'Loaded Content', description: 'This content was loaded successfully!' });
setIsLoading(false);
}, 2000);
}, []);
if (isLoading) {
return (
<div style={{ padding: '20px' }}>
<ContentLoader
viewBox="0 0 400 160"
height={160}
width={400}
backgroundColor="#f3f3f3"
foregroundColor="#ecebeb"
>
<rect x="0" y="0" rx="5" ry="5" width="400" height="160" />
</ContentLoader>
</div>
);
}
return (
<div style={{ padding: '20px' }}>
<h2>{data.title}</h2>
<p>{data.description}</p>
</div>
);
}
export default ContentLoaderExample;
Update your App.jsx:
// src/App.jsx
import React from 'react';
import ContentLoaderExample from './ContentLoaderExample';
import './App.css';
function App() {
return (
<div className="App">
<ContentLoaderExample />
</div>
);
}
export default App;
This creates a basic skeleton loader that displays while content is loading.
Understanding the Basics
react-content-loader provides several key features:
- ContentLoader component: Main component for creating custom loaders
- Pre-defined loaders: Facebook, Instagram, Code, List, BulletList patterns
- SVG-based: Uses SVG for smooth animations
- Customizable: Colors, speed, size, and shapes
- Responsive: Works with different screen sizes
Key concepts for advanced usage:
-
SVG Shapes: Use
<rect>,<circle>, and other SVG elements to create loaders - viewBox: Defines the coordinate system and aspect ratio
- Animation: Automatic shimmer animation effect
- Customization: Control colors, speed, and animation behavior
- Pre-defined Patterns: Use ready-made loaders for common layouts
Here's an example with pre-defined loaders:
// src/PredefinedLoadersExample.jsx
import React, { useState } from 'react';
import { Facebook, Instagram, Code, List, BulletList } from 'react-content-loader';
function PredefinedLoadersExample() {
const [selectedLoader, setSelectedLoader] = useState('Facebook');
const loaders = {
Facebook: <Facebook />,
Instagram: <Instagram />,
Code: <Code />,
List: <List />,
BulletList: <BulletList />
};
return (
<div style={{ padding: '20px' }}>
<h2>Pre-defined Loaders</h2>
<div style={{ marginBottom: '20px' }}>
<label>Select Loader: </label>
<select
value={selectedLoader}
onChange={(e) => setSelectedLoader(e.target.value)}
style={{ padding: '5px', marginLeft: '10px' }}
>
{Object.keys(loaders).map(type => (
<option key={type} value={type}>{type}</option>
))}
</select>
</div>
<div style={{ border: '1px solid #ddd', padding: '20px', borderRadius: '8px' }}>
{loaders[selectedLoader]}
</div>
</div>
);
}
export default PredefinedLoadersExample;
Practical Example / Building Something Real
Let's build a comprehensive skeleton loader system with custom patterns:
// src/CardSkeletonLoader.jsx
import React from 'react';
import ContentLoader from 'react-content-loader';
function CardSkeletonLoader() {
return (
<ContentLoader
viewBox="0 0 400 200"
height={200}
width={400}
backgroundColor="#f3f3f3"
foregroundColor="#ecebeb"
>
{/* Avatar */}
<circle cx="50" cy="50" r="30" />
{/* Title */}
<rect x="100" y="20" rx="4" ry="4" width="200" height="20" />
{/* Subtitle */}
<rect x="100" y="50" rx="3" ry="3" width="150" height="15" />
{/* Content lines */}
<rect x="20" y="100" rx="3" ry="3" width="360" height="10" />
<rect x="20" y="120" rx="3" ry="3" width="320" height="10" />
<rect x="20" y="140" rx="3" ry="3" width="280" height="10" />
{/* Button */}
<rect x="20" y="170" rx="5" ry="5" width="100" height="25" />
</ContentLoader>
);
}
export default CardSkeletonLoader;
Create a list skeleton loader:
// src/ListSkeletonLoader.jsx
import React from 'react';
import ContentLoader from 'react-content-loader';
function ListSkeletonLoader({ items = 3 }) {
return (
<div>
{Array.from({ length: items }).map((_, index) => (
<ContentLoader
key={index}
viewBox="0 0 400 80"
height={80}
width={400}
backgroundColor="#f3f3f3"
foregroundColor="#ecebeb"
style={{ marginBottom: '10px' }}
>
{/* Icon */}
<rect x="10" y="10" rx="5" ry="5" width="60" height="60" />
{/* Title */}
<rect x="80" y="20" rx="4" ry="4" width="200" height="15" />
{/* Description */}
<rect x="80" y="45" rx="3" ry="3" width="300" height="10" />
</ContentLoader>
))}
</div>
);
}
export default ListSkeletonLoader;
Create a table skeleton loader:
// src/TableSkeletonLoader.jsx
import React from 'react';
import ContentLoader from 'react-content-loader';
function TableSkeletonLoader({ rows = 5, columns = 4 }) {
const cellWidth = 380 / columns;
const cellHeight = 30;
const rowHeight = 50;
return (
<ContentLoader
viewBox={`0 0 400 ${rows * rowHeight + 40}`}
height={rows * rowHeight + 40}
width={400}
backgroundColor="#f3f3f3"
foregroundColor="#ecebeb"
>
{/* Header row */}
{Array.from({ length: columns }).map((_, colIndex) => (
<rect
key={`header-${colIndex}`}
x={10 + colIndex * cellWidth}
y={10}
rx="3"
ry="3"
width={cellWidth - 20}
height={cellHeight}
/>
))}
{/* Data rows */}
{Array.from({ length: rows }).map((_, rowIndex) =>
Array.from({ length: columns }).map((_, colIndex) => (
<rect
key={`row-${rowIndex}-col-${colIndex}`}
x={10 + colIndex * cellWidth}
y={50 + rowIndex * rowHeight}
rx="3"
ry="3"
width={cellWidth - 20}
height={cellHeight}
/>
))
)}
</ContentLoader>
);
}
export default TableSkeletonLoader;
Now create a complete loading system:
// src/AdvancedLoadingSystem.jsx
import React, { useState, useEffect } from 'react';
import CardSkeletonLoader from './CardSkeletonLoader';
import ListSkeletonLoader from './ListSkeletonLoader';
import TableSkeletonLoader from './TableSkeletonLoader';
function AdvancedLoadingSystem() {
const [loadingStates, setLoadingStates] = useState({
card: true,
list: true,
table: true
});
const [data, setData] = useState({
card: null,
list: null,
table: null
});
useEffect(() => {
// Simulate loading card data
setTimeout(() => {
setData(prev => ({
...prev,
card: { title: 'Card Title', description: 'Card description' }
}));
setLoadingStates(prev => ({ ...prev, card: false }));
}, 2000);
// Simulate loading list data
setTimeout(() => {
setData(prev => ({
...prev,
list: [
{ id: 1, title: 'Item 1', description: 'Description 1' },
{ id: 2, title: 'Item 2', description: 'Description 2' },
{ id: 3, title: 'Item 3', description: 'Description 3' }
]
}));
setLoadingStates(prev => ({ ...prev, list: false }));
}, 2500);
// Simulate loading table data
setTimeout(() => {
setData(prev => ({
...prev,
table: [
{ id: 1, name: 'John', email: 'john@example.com' },
{ id: 2, name: 'Jane', email: 'jane@example.com' },
{ id: 3, name: 'Bob', email: 'bob@example.com' }
]
}));
setLoadingStates(prev => ({ ...prev, table: false }));
}, 3000);
}, []);
return (
<div style={{ padding: '20px' }}>
<h1>Advanced Loading System</h1>
{/* Card Section */}
<section style={{ marginBottom: '40px', padding: '20px', border: '1px solid #ddd', borderRadius: '8px' }}>
<h2>Card Loading</h2>
{loadingStates.card ? (
<CardSkeletonLoader />
) : (
<div style={{ padding: '20px', backgroundColor: '#f8f9fa', borderRadius: '8px' }}>
<h3>{data.card?.title}</h3>
<p>{data.card?.description}</p>
</div>
)}
</section>
{/* List Section */}
<section style={{ marginBottom: '40px', padding: '20px', border: '1px solid #ddd', borderRadius: '8px' }}>
<h2>List Loading</h2>
{loadingStates.list ? (
<ListSkeletonLoader items={3} />
) : (
<div>
{data.list?.map(item => (
<div key={item.id} style={{ padding: '15px', marginBottom: '10px', backgroundColor: '#f8f9fa', borderRadius: '4px' }}>
<h4>{item.title}</h4>
<p>{item.description}</p>
</div>
))}
</div>
)}
</section>
{/* Table Section */}
<section style={{ marginBottom: '40px', padding: '20px', border: '1px solid #ddd', borderRadius: '8px' }}>
<h2>Table Loading</h2>
{loadingStates.table ? (
<TableSkeletonLoader rows={3} columns={3} />
) : (
<table style={{ width: '100%', borderCollapse: 'collapse' }}>
<thead>
<tr style={{ backgroundColor: '#007bff', color: 'white' }}>
<th style={{ padding: '10px', textAlign: 'left' }}>ID</th>
<th style={{ padding: '10px', textAlign: 'left' }}>Name</th>
<th style={{ padding: '10px', textAlign: 'left' }}>Email</th>
</tr>
</thead>
<tbody>
{data.table?.map(row => (
<tr key={row.id} style={{ borderBottom: '1px solid #ddd' }}>
<td style={{ padding: '10px' }}>{row.id}</td>
<td style={{ padding: '10px' }}>{row.name}</td>
<td style={{ padding: '10px' }}>{row.email}</td>
</tr>
))}
</tbody>
</table>
)}
</section>
</div>
);
}
export default AdvancedLoadingSystem;
Update your App.jsx:
// src/App.jsx
import React from 'react';
import AdvancedLoadingSystem from './AdvancedLoadingSystem';
import PredefinedLoadersExample from './PredefinedLoadersExample';
import './App.css';
function App() {
return (
<div className="App">
<AdvancedLoadingSystem />
<PredefinedLoadersExample />
</div>
);
}
export default App;
This example demonstrates:
- Custom skeleton loaders for cards, lists, and tables
- Pre-defined loader patterns
- Multiple loading states
- Responsive skeleton structures
- Matching content layout
Common Issues / Troubleshooting
Loader not displaying: Make sure you're using SVG elements (
<rect>,<circle>) insideContentLoader. Regular HTML elements won't work.Sizing issues: Use the
viewBoxprop to define the coordinate system. Thewidthandheightprops control the rendered size.Animation not working: Check that
animateprop istrue(default). Also ensure you're using valid SVG shapes.Colors not applying: Use
backgroundColorandforegroundColorprops to customize colors. These control the shimmer animation colors.Layout mismatch: Design your skeleton loader to match your actual content layout. Use the same spacing and dimensions for best results.
Performance: react-content-loader uses SVG which is performant, but if you have many loaders, consider using conditional rendering to only show them when needed.
Next Steps
Now that you have an advanced understanding of react-content-loader:
- Explore all pre-defined loader patterns
- Learn about advanced SVG customization
- Create loaders that match your exact content structure
- Implement responsive skeleton loaders
- Add skeleton loaders to data fetching hooks
- Learn about other skeleton loader libraries
- Check the official repository: https://github.com/danilowoz/react-content-loader
- Look for part 55 of this series for more advanced topics
Summary
You've successfully integrated react-content-loader into your React application with advanced features including custom skeleton loaders for cards, lists, and tables, pre-defined patterns, and comprehensive loading states. react-content-loader provides a flexible, SVG-based solution for creating professional skeleton loaders that improve perceived performance.
SEO Keywords
react-content-loader
React skeleton loader
react-content-loader tutorial
React placeholder loading
react-content-loader installation
React SVG skeleton
react-content-loader example
React loading placeholder
react-content-loader setup
React Facebook loader
react-content-loader customization
React skeleton pattern
react-content-loader SVG
React loading library
react-content-loader getting started
Top comments (0)