Bootstrap - Bootstrap Spinners and Loading Indicators
Bootstrap Spinners are visual indicators used to show that a process is currently running. They are especially useful when a webpage needs time to complete an operation such as loading data from a server, submitting a form, processing a request, uploading a file, or waiting for an API response.
Bootstrap provides built-in spinner classes, so developers do not need to create loading animations from scratch using custom CSS. Spinners can be easily customized in terms of style, size, color, and placement.
1. What is a Spinner?
A spinner is a small animated element that indicates that the application is busy performing an operation.
For example, when a user clicks a "Load Data" button, the application may need several seconds to retrieve information from a server. Instead of leaving the user wondering whether the button worked, a spinner can be displayed during the process.
A basic Bootstrap spinner can be created using:
<div class="spinner-border" role="status">
<span class="visually-hidden">Loading...</span>
</div>
The spinner-border class creates a rotating circular border.
The role="status" attribute communicates that the element represents a status or progress state.
The visually-hidden class hides the text visually while keeping it available to screen readers.
2. Border Spinner
The border spinner is the most commonly used Bootstrap spinner.
<div class="spinner-border" role="status">
<span class="visually-hidden">Loading...</span>
</div>
It creates a circular rotating border with an empty center.
The animation is automatically provided by Bootstrap's CSS.
You can also change its color using Bootstrap's text-color classes.
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
Another example is:
<div class="spinner-border text-success" role="status">
<span class="visually-hidden">Loading...</span>
</div>
Here, text-success changes the spinner's color.
Other contextual color classes can also be used, such as:
text-primary
text-secondary
text-success
text-danger
text-warning
text-info
text-light
text-dark
3. Growing Spinner
Bootstrap also provides a growing spinner.
Instead of rotating around a border, the growing spinner expands and contracts to create a pulsing loading effect.
Example:
<div class="spinner-grow" role="status">
<span class="visually-hidden">Loading...</span>
</div>
The spinner-grow class creates this animation.
You can also apply a color class:
<div class="spinner-grow text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
The growing spinner can be useful when you want a softer loading animation compared with the traditional rotating border spinner.
4. Spinner Sizes
Bootstrap allows you to create smaller spinners using the .spinner-border-sm and .spinner-grow-sm classes.
For a small border spinner:
<div class="spinner-border spinner-border-sm" role="status">
<span class="visually-hidden">Loading...</span>
</div>
For a small growing spinner:
<div class="spinner-grow spinner-grow-sm" role="status">
<span class="visually-hidden">Loading...</span>
</div>
Small spinners are particularly useful inside buttons or compact interface elements.
5. Spinners Inside Buttons
One of the most practical uses of Bootstrap spinners is inside buttons.
For example:
<button class="btn btn-primary" type="button" disabled>
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
Loading...
</button>
The spinner communicates that an operation is in progress.
The disabled attribute prevents the user from clicking the button repeatedly while the operation is being processed.
A growing spinner can also be used:
<button class="btn btn-primary" type="button" disabled>
<span class="spinner-grow spinner-grow-sm" role="status" aria-hidden="true"></span>
Loading...
</button>
This approach is commonly used for login, registration, payment processing, search, and data submission operations.
6. Spinner With JavaScript
A spinner becomes much more useful when it is displayed dynamically using JavaScript.
Consider a button:
<button id="loadButton" class="btn btn-primary">
Load Data
</button>
JavaScript can replace the button content when the user clicks it:
document.getElementById("loadButton").addEventListener("click", function () {
this.disabled = true;
this.innerHTML = `
<span class="spinner-border spinner-border-sm" role="status"></span>
Loading...
`;
});
When the button is clicked, it becomes disabled and displays a spinner.
In a real application, the spinner should normally be removed after the operation finishes.
For example:
setTimeout(function () {
const button = document.getElementById("loadButton");
button.disabled = false;
button.innerHTML = "Load Data";
}, 3000);
Here, the button displays the spinner for three seconds before returning to its original state.
7. Using Spinners With AJAX or Fetch
Spinners are particularly useful when retrieving information asynchronously.
For example:
<button id="loadButton" class="btn btn-primary">
Load Users
</button>
<div id="result"></div>
JavaScript:
const button = document.getElementById("loadButton");
const result = document.getElementById("result");
button.addEventListener("click", async function () {
button.disabled = true;
button.innerHTML = `
<span class="spinner-border spinner-border-sm" role="status"></span>
Loading...
`;
try {
const response = await fetch("/users");
const data = await response.json();
result.innerHTML = JSON.stringify(data);
} catch (error) {
result.innerHTML = "Unable to load users.";
}
button.disabled = false;
button.innerHTML = "Load Users";
});
The spinner appears while the request is being processed. Once the server responds, the spinner is removed and the button returns to its normal state.
This creates a better user experience because users can clearly see that the application is working.
8. Accessibility Considerations
A loading indicator should not depend only on visual animation.
For example:
<div class="spinner-border" role="status">
<span class="visually-hidden">Loading...</span>
</div>
The text Loading... provides useful information to users who rely on screen readers.
The role="status" attribute helps assistive technologies understand that the element represents a status message.
When the spinner is placed inside a button and the button already contains visible text such as "Loading", you may use:
<button class="btn btn-primary" type="button" disabled>
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
Loading...
</button>
Here, aria-hidden="true" prevents the decorative spinner from being unnecessarily announced by screen readers because the visible "Loading..." text already communicates the state.
9. Choosing Between Border and Growing Spinners
Bootstrap provides two primary spinner styles.
The spinner-border style is appropriate when you want a conventional rotating loading indicator. It is commonly used for page loading, data retrieval, and button operations.
The spinner-grow style produces an expanding and contracting animation. It can be useful when you want a less conventional loading indicator or when a pulsing effect fits the interface better.
The choice is mainly based on the design and context of the application.
10. Common Applications
Bootstrap spinners can be used in many situations, including:
-
Loading information from an API
-
Submitting forms
-
Processing login requests
-
Uploading files
-
Downloading information
-
Performing database operations
-
Loading search results
-
Processing payments
-
Waiting for server responses
-
Loading sections of a webpage dynamically
For example, a website may display a spinner while a product list is being retrieved from the server. Once the products arrive, the spinner can be removed and the actual content can be displayed.
11. Important Best Practices
Spinners should be used to communicate an actual ongoing process. They should not be displayed unnecessarily for very fast operations because this can make the interface feel slower.
It is also important to disable buttons when appropriate. If a user can repeatedly click a button while a request is being processed, the application may accidentally submit the same request multiple times.
The loading state should also be removed when the operation completes, whether it succeeds or fails. A spinner that continues indefinitely can make users think the application has stopped responding.
For longer operations, it can be helpful to provide additional information rather than displaying only an animation. For example, an upload interface might display "Uploading file..." or a percentage-based progress indicator when the actual progress is available.
12. Complete Example
The following example demonstrates a Bootstrap spinner inside a button:
<!DOCTYPE html>
<html>
<head>
<title>Bootstrap Spinner Example</title>
<link
href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
rel="stylesheet">
</head>
<body>
<div class="container mt-5">
<button id="submitButton" class="btn btn-primary">
Submit
</button>
</div>
<script>
document.getElementById("submitButton").addEventListener("click", function () {
const button = this;
button.disabled = true;
button.innerHTML = `
<span
class="spinner-border spinner-border-sm"
role="status"
aria-hidden="true">
</span>
Processing...
`;
setTimeout(function () {
button.disabled = false;
button.innerHTML = "Submit";
}, 3000);
});
</script>
</body>
</html>
When the user clicks the button, it changes from "Submit" to "Processing..." and displays a small spinner. After three seconds, the button returns to its original state.
Conclusion
Bootstrap Spinners provide a simple and consistent way to communicate loading and processing states in web applications. The framework offers both rotating border spinners and growing spinners, along with small variants and contextual colors. They can be used independently or integrated into buttons and JavaScript-driven operations.
The most important principle is to use spinners as part of a clear loading-state design. A good implementation should indicate when processing starts, prevent inappropriate repeated actions, provide accessible status information, and remove the spinner when processing finishes.