Bootstrap Spinner: Loading Spinners in Bootstrap 5
Bootstrap spinners are loading indicators made entirely in CSS: a spinning ring or a pulsing dot that shows something is happening, such as a page section loading or a form submitting. They need no JavaScript and no images. This guide covers both styles, sizes, colors, spinners inside buttons, centering, accessibility, and how to show and hide a spinner while data loads. Everything is for Bootstrap 5.3.
The two spinner styles
<!-- Border spinner: a rotating ring -->
<div class="spinner-border" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<!-- Growing spinner: a dot that grows and fades -->
<div class="spinner-grow" role="status">
<span class="visually-hidden">Loading...</span>
</div>
role="status" and the visually hidden text let screen readers announce “Loading…” while sighted users see only the animation. Change the text to say what is loading, such as “Loading results…”.
Colors
Spinners use the current text color, so any text color utility changes them:
<div class="spinner-border text-primary" role="status"><span class="visually-hidden">Loading...</span></div>
<div class="spinner-border text-success" role="status"><span class="visually-hidden">Loading...</span></div>
<div class="spinner-grow text-danger" role="status"><span class="visually-hidden">Loading...</span></div>
Every theme color works: text-primary, text-secondary, text-success, text-danger, text-warning, text-info, text-light, and text-dark. For a custom color, set color in your CSS.
Sizes
The default spinner is 2rem (32px). Add -sm for a 1rem version:
<div class="spinner-border spinner-border-sm" role="status"><span class="visually-hidden">Loading...</span></div>
<div class="spinner-grow spinner-grow-sm" role="status"><span class="visually-hidden">Loading...</span></div>
For any other size, set the width and height:
<div class="spinner-border" style="width: 4rem; height: 4rem;" role="status">
<span class="visually-hidden">Loading...</span>
</div>
Or use the CSS variables, which also let you change the ring’s thickness and the speed:
.spinner-lg {
--bs-spinner-width: 4rem;
--bs-spinner-height: 4rem;
--bs-spinner-border-width: .35em;
--bs-spinner-animation-speed: 1s;
}
A spinner inside a button
The most common use: show that a form is submitting.
<button class="btn btn-primary" type="button" disabled>
<span class="spinner-border spinner-border-sm" aria-hidden="true"></span>
<span role="status">Saving...</span>
</button>
The spinner is decorative here (aria-hidden="true"), because the button’s text already says what is happening. Disable the button while it works so the form can’t be submitted twice. To show only the spinner, keep the text for screen readers with class="visually-hidden".
Center a spinner
In a section, center it with flex utilities:
<div class="d-flex justify-content-center py-5">
<div class="spinner-border" role="status"><span class="visually-hidden">Loading...</span></div>
</div>
Over a whole card or page, use a full-size overlay:
<div class="position-relative">
<!-- your content -->
<div class="position-absolute top-0 start-0 w-100 h-100 d-flex align-items-center justify-content-center bg-body bg-opacity-75">
<div class="spinner-border text-primary" role="status"><span class="visually-hidden">Loading...</span></div>
</div>
</div>
For a spinner beside text, such as “Loading…”, put both in a d-flex align-items-center gap-2 container. More centering options are in how to center a div in Bootstrap.
Show and hide a spinner while loading
<div id="results"></div>
<div id="results-spinner" class="spinner-border d-none" role="status">
<span class="visually-hidden">Loading results...</span>
</div>
const spinner = document.querySelector('#results-spinner')
const results = document.querySelector('#results')
async function loadResults() {
spinner.classList.remove('d-none')
try {
const response = await fetch('/api/results')
results.textContent = await response.text()
} finally {
spinner.classList.add('d-none')
}
}
d-none hides the spinner, and removing it shows it. The finally block hides the spinner even if the request fails, so it never spins forever.
When you know how far along the work is, such as a file upload, a progress bar tells people more than a spinner. To confirm that the action finished, show a toast such as “Changes saved”.
Reduced motion
When a visitor has turned on “reduce motion” in their operating system, Bootstrap slows spinners to half speed rather than stopping them, because the animation is how they communicate. The text in the visually hidden span still announces the loading state.
Customize with Sass
Set these before importing Bootstrap:
| Variable | Default |
|---|---|
$spinner-width, $spinner-height |
2rem |
$spinner-border-width |
.25em |
$spinner-animation-speed |
.75s |
$spinner-width-sm, $spinner-height-sm |
1rem |
$spinner-border-width-sm |
.2em |
See Bootstrap Sass variables explained for how overrides work.
FAQ
How do I add a loading spinner in Bootstrap 5?
Add <div class="spinner-border" role="status"><span class="visually-hidden">Loading...</span></div>. Use spinner-grow instead for a pulsing dot. No JavaScript is needed; the animation is pure CSS.
How do I change the size of a Bootstrap spinner?
Add spinner-border-sm or spinner-grow-sm for a small 1rem spinner. For other sizes, set width and height on the spinner, or the --bs-spinner-width and --bs-spinner-height CSS variables.
How do I change the color of a Bootstrap spinner?
Add a text color utility such as text-primary or text-danger. Spinners use the current text color, so a custom color in CSS also works.
How do I put a spinner in a Bootstrap button?
Place <span class="spinner-border spinner-border-sm" aria-hidden="true"></span> inside the button before its text, and disable the button while the action runs so it can’t be clicked twice.
How do I center a spinner in Bootstrap?
Wrap it in <div class="d-flex justify-content-center">. To center it over a card or section, use an absolutely positioned overlay with d-flex align-items-center justify-content-center.
Try it in the builder
Make these changes visually with a live preview, then export clean Bootstrap Sass or CSS.
Open the Builder