Bootstrap 5 Tutorial
v5.3.0Bootstrap 5 Tutorial
Spinners in Bootstrap 5
Spinners: Indicate loading state of a component or page with Bootstrap spinners.
Border Spinner
Border Spinner (Default)
Loading...
<!-- Border spinner -->
<div class="spinner-border" role="status">
<span class="visually-hidden">Loading...</span>
</div>Spinner Colors
Color Variations
<!-- Color variations -->
<div class="spinner-border text-primary" role="status"></div>
<div class="spinner-border text-secondary" role="status"></div>
<div class="spinner-border text-success" role="status"></div>
<div class="spinner-border text-danger" role="status"></div>
<div class="spinner-border text-warning" role="status"></div>
<div class="spinner-border text-info" role="status"></div>
<div class="spinner-border text-dark" role="status"></div>Growing Spinner
Border Spinner
Loading...
spinner-borderGrowing Spinner
Loading...
spinner-growGrowing Spinner Colors
Growing Spinner Variations
<!-- Growing spinner colors -->
<div class="spinner-grow text-primary" role="status"></div>
<div class="spinner-grow text-secondary" role="status"></div>
<div class="spinner-grow text-success" role="status"></div>
<div class="spinner-grow text-danger" role="status"></div>
<div class="spinner-grow text-warning" role="status"></div>
<div class="spinner-grow text-info" role="status"></div>
<div class="spinner-grow text-dark" role="status"></div>Spinner Sizes
Size Options
Small (
spinner-border-sm)Default (2rem)
Large (3rem)
Extra Large (5rem)
Growing Spinner Sizes
<!-- Size variations -->
<!-- Small -->
<div class="spinner-border spinner-border-sm"></div>
<div class="spinner-grow spinner-grow-sm"></div>
<!-- Custom sizes -->
<div class="spinner-border" style="width: 3rem; height: 3rem;"></div>
<div class="spinner-grow" style="width: 3rem; height: 3rem;"></div>
<!-- Extra large -->
<div class="spinner-border" style="width: 5rem; height: 5rem;"></div>Spinners with Text
Spinner with Loading Text
Loading...
Please wait while we process your request...
<!-- Spinner with text -->
<div class="d-flex align-items-center">
<div class="spinner-border text-primary me-3" role="status"></div>
<strong>Loading...</strong>
</div>
<!-- Spinner in button -->
<button class="btn btn-primary" disabled>
<span class="spinner-border spinner-border-sm me-2" role="status"></span>
Loading...
</button>
<!-- Growing spinner with text -->
<div class="d-flex align-items-center">
<div class="spinner-grow text-success me-3" role="status"></div>
<span>Processing...</span>
</div>Interactive Example
Dynamic Spinner Demo
Content Loaded Successfully!
Your data has been loaded and is ready to view.
// React/JavaScript code for interactive spinner
const [loading, setLoading] = useState(false);
const [size, setSize] = useState('default');
const toggleLoading = () => {
setLoading(!loading);
};
const simulateLoad = () => {
setLoading(true);
setTimeout(() => setLoading(false), 3000);
};
// HTML Structure
{loading ? (
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
) : (
<div>Content loaded</div>
)}
<button onclick="simulateLoad()">Start Loading</button>
<button onclick="toggleLoading()">Toggle Loading</button>Real-World Examples
Practical Use Cases
Form Submission
Data Table Loading
| ID | Name | Status |
|---|---|---|
| 1 | John Doe | Active |
Content Loading
Page Loading
Loading Dashboard
Please wait while we prepare your dashboard...
Accessibility Features
Accessibility Best Practices
- Always include
role=&qout;status&qout; - Use
aria-labelor text content for screen readers - Include
visually-hiddentext for better accessibility - Ensure spinners don't create flashing that could trigger seizures
- Provide alternative content when spinner is hidden
- Test with screen readers
Custom Styling
Custom Dual Spinner
Pulse Animation
/* Custom CSS for spinners */
.custom-spinner {
width: 4rem;
height: 4rem;
border: 0.5em solid transparent;
border-top-color: #3498db;
border-right-color: #3498db;
border-radius: 50%;
animation: custom-spin 1s linear infinite;
}
.custom-spinner-inner {
width: 100%;
height: 100%;
border: 0.25em solid transparent;
border-top-color: #e74c3c;
border-radius: 50%;
animation: custom-spin-reverse 0.5s linear infinite;
}
@keyframes custom-spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
@keyframes custom-spin-reverse {
0% { transform: rotate(0deg); }
100% { transform: rotate(-360deg); }
}
.pulse-spinner {
width: 3rem;
height: 3rem;
background-color: #9b59b6;
border-radius: 50%;
animation: pulse 1s ease-in-out infinite;
}
@keyframes pulse {
0%, 100% { transform: scale(1); opacity: 1; }
50% { transform: scale(1.2); opacity: 0.7; }
}JavaScript Integration
JavaScript API Examples
// JavaScript for dynamic spinner control
// Show spinner
function showSpinner(spinnerId) {
const spinner = document.getElementById(spinnerId);
spinner.style.display = 'block';
spinner.setAttribute('aria-hidden', 'false');
}
// Hide spinner
function hideSpinner(spinnerId) {
const spinner = document.getElementById(spinnerId);
spinner.style.display = 'none';
spinner.setAttribute('aria-hidden', 'true');
}
// Toggle spinner
function toggleSpinner(spinnerId) {
const spinner = document.getElementById(spinnerId);
const isHidden = spinner.style.display === 'none';
spinner.style.display = isHidden ? 'block' : 'none';
spinner.setAttribute('aria-hidden', isHidden ? 'false' : 'true');
}
// Show spinner during AJAX request
function fetchWithSpinner(url, spinnerId) {
showSpinner(spinnerId);
fetch(url)
.then(response => response.json())
.then(data => {
hideSpinner(spinnerId);
processData(data);
})
.catch(error => {
hideSpinner(spinnerId);
showError(error);
});
}
// Button click handler with spinner
document.getElementById('submitBtn').addEventListener('click', function() {
const button = this;
const originalText = button.innerHTML;
// Show spinner in button
button.innerHTML = `
<span class="spinner-border spinner-border-sm me-2" role="status"></span>
Loading...
`;
button.disabled = true;
// Simulate API call
setTimeout(() => {
button.innerHTML = originalText;
button.disabled = false;
showSuccessMessage();
}, 2000);
});
// Show full page spinner
function showFullPageSpinner() {
const spinner = document.createElement('div');
spinner.id = 'fullPageSpinner';
spinner.className = 'position-fixed top-0 left-0 w-100 h-100 d-flex justify-content-center align-items-center bg-dark bg-opacity-75';
spinner.style.zIndex = '9999';
spinner.innerHTML = `
<div class="text-center">
<div class="spinner-border text-light" style="width: 4rem; height: 4rem;" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<p class="text-light mt-3">Loading, please wait...</p>
</div>
`;
document.body.appendChild(spinner);
}
// Hide full page spinner
function hideFullPageSpinner() {
const spinner = document.getElementById('fullPageSpinner');
if (spinner) {
spinner.remove();
}
}