Spinners
Spinners tell people that something is happening right now. The examples cover the border and grow styles, colours, sizes, speed and thickness, plus spinners placed in buttons, inputs, cards, tables, alerts and dialogs - always with a status text for screen readers.
1Border spinner
A rotating ring - the default loading indicator.
<div class="spinner-border" role="status">
<span class="sr-only">Loading...</span>
</div>2Colored border spinners
Text colour utilities change the spinner colour.
<div class="flex flex-wrap gap-2">
<div class="spinner-border text-primary-ink" role="status">
<span class="sr-only">Loading...</span>
</div>
<div class="spinner-border text-secondary" role="status">
<span class="sr-only">Loading...</span>
</div>
<div class="spinner-border text-success-emphasis" role="status">
<span class="sr-only">Loading...</span>
</div>
<div class="spinner-border text-danger-emphasis" role="status">
<span class="sr-only">Loading...</span>
</div>
<div class="spinner-border text-warning-emphasis" role="status">
<span class="sr-only">Loading...</span>
</div>
<div class="spinner-border text-info-emphasis" role="status">
<span class="sr-only">Loading...</span>
</div>
<div class="spinner-border text-dark" role="status">
<span class="sr-only">Loading...</span>
</div>
</div>3Grow spinner
A dot that grows and fades instead of spinning.
<div class="spinner-grow" role="status">
<span class="sr-only">Loading...</span>
</div>4Colored grow spinners
The grow spinner in every theme colour.
<div class="flex flex-wrap gap-2">
<div class="spinner-grow text-primary-ink" role="status">
<span class="sr-only">Loading...</span>
</div>
<div class="spinner-grow text-secondary" role="status">
<span class="sr-only">Loading...</span>
</div>
<div class="spinner-grow text-success-emphasis" role="status">
<span class="sr-only">Loading...</span>
</div>
<div class="spinner-grow text-danger-emphasis" role="status">
<span class="sr-only">Loading...</span>
</div>
<div class="spinner-grow text-warning-emphasis" role="status">
<span class="sr-only">Loading...</span>
</div>
<div class="spinner-grow text-info-emphasis" role="status">
<span class="sr-only">Loading...</span>
</div>
<div class="spinner-grow text-dark" role="status">
<span class="sr-only">Loading...</span>
</div>
</div>5Sizes
<code>.spinner-border-sm</code> / <code>.spinner-grow-sm</code>, or any size through width and height.
<div class="flex flex-wrap items-center gap-4">
<div class="spinner-border spinner-border-sm" role="status">
<span class="sr-only">Loading...</span>
</div>
<div class="spinner-grow spinner-grow-sm" role="status">
<span class="sr-only">Loading...</span>
</div>
<div class="spinner-border" role="status">
<span class="sr-only">Loading...</span>
</div>
<div class="spinner-border text-primary-ink" role="status" style="width: 3rem; height: 3rem;">
<span class="sr-only">Loading...</span>
</div>
<div class="spinner-grow text-primary-ink" role="status" style="width: 3rem; height: 3rem;">
<span class="sr-only">Loading...</span>
</div>
</div>6Loading buttons
Disabled buttons with a small spinner while a request runs.
<div class="flex flex-wrap gap-2">
<button class="btn btn-primary" type="button" disabled><span class="spinner-border spinner-border-sm" aria-hidden="true"></span><span class="sr-only" role="status">Loading...</span></button>
<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>
<button class="btn btn-outline-success" type="button" disabled><span class="spinner-grow spinner-grow-sm" aria-hidden="true"></span> <span role="status">Sending</span></button>
</div>7Alignment with flex
Center a spinner, or push it to the end of a line of text.
<div class="flex justify-center mb-4">
<div class="spinner-border" role="status">
<span class="sr-only">Loading...</span>
</div>
</div>
<div class="flex items-center border rounded-md p-2">
<strong role="status">Loading experiences...</strong>
<div class="spinner-border spinner-border-sm ms-auto" aria-hidden="true">
</div>
</div>8Text alignment
Text alignment utilities place an inline spinner left, center or right.
<div class="text-start">
<div class="spinner-border spinner-border-sm" role="status">
<span class="sr-only">Loading...</span>
</div>
</div>
<div class="text-center">
<div class="spinner-border spinner-border-sm" role="status">
<span class="sr-only">Loading...</span>
</div>
</div>
<div class="text-end">
<div class="spinner-border spinner-border-sm" role="status">
<span class="sr-only">Loading...</span>
</div>
</div>9Card overlay
A translucent overlay with a spinner covers a card that is updating.
<div class="card relative overflow-hidden" style="max-width:360px">
<div class="card-body">
<h3 class="h6 card-title">Speaker management</h3>
<p class="card-text small">The venue is a short walk from the station and fully accessible.</p>
<a href="#" class="btn btn-sm btn-primary">Open</a>
</div>
<div class="absolute top-0 start-0 w-full h-full flex flex-col items-center justify-center bg-page" style="--ui-bg-opacity:.75">
<div class="spinner-border text-primary-ink" aria-hidden="true">
</div>
<span class="small mt-2" role="status">Updating...</span>
</div>
</div>10Inside an input group
A spinner in the input group addon while search results load.
<div class="input-group" style="max-width:420px">
<label for="spin-search-1218" class="sr-only">Search</label>
<input type="search" class="form-control" id="spin-search-1218" value="team"><span class="input-group-text"><span class="spinner-border spinner-border-sm text-secondary" role="status"><span class="sr-only">Searching...</span></span></span>
</div>11Custom speed
Change the animation speed with <code>--ui-spinner-animation-speed</code>.
<div class="flex gap-4 items-center">
<div class="spinner-border text-primary-ink" role="status" style="--ui-spinner-animation-speed: .4s">
<span class="sr-only">Loading...</span>
</div>
<div class="spinner-border text-primary-ink" role="status">
<span class="sr-only">Loading...</span>
</div>
<div class="spinner-border text-primary-ink" role="status" style="--ui-spinner-animation-speed: 2.5s">
<span class="sr-only">Loading...</span>
</div>
<small class="text-muted">fast / default / slow</small>
</div>12Custom thickness
<code>--ui-spinner-border-width</code> makes the ring thinner or bolder.
<div class="flex gap-4 items-center">
<div class="spinner-border text-success-emphasis" role="status" style="--ui-spinner-border-width: 1px; width: 2.5rem; height: 2.5rem">
<span class="sr-only">Loading...</span>
</div>
<div class="spinner-border text-success-emphasis" role="status" style="--ui-spinner-border-width: .5em; width: 2.5rem; height: 2.5rem">
<span class="sr-only">Loading...</span>
</div>
<div class="spinner-border text-success-emphasis" role="status" style="--ui-spinner-border-width: 2px; width: 4rem; height: 4rem">
<span class="sr-only">Loading...</span>
</div>
</div>13Process steps
Finished steps show a check, the running step a spinner, upcoming steps a muted circle.
- Files uploaded
- Data checked
- Building preview...
- Publishing
<ul class="list-unstyled mb-0">
<li class="flex items-center gap-2 mb-2 text-success-emphasis"><i class="bi bi-check-circle-fill" aria-hidden="true"></i> Files uploaded</li>
<li class="flex items-center gap-2 mb-2 text-success-emphasis"><i class="bi bi-check-circle-fill" aria-hidden="true"></i> Data checked</li>
<li class="flex items-center gap-2 mb-2"><span class="spinner-border spinner-border-sm text-primary-ink" aria-hidden="true"></span><span role="status">Building preview...</span></li>
<li class="flex items-center gap-2 text-muted"><i class="bi bi-circle" aria-hidden="true"></i> Publishing</li>
</ul>14Table loading row
A full width row with a spinner while table data is fetched.
| Order | Customer | Total |
|---|---|---|
| Loading orders... | ||
<div class="table-responsive">
<table class="table mb-0">
<thead>
<tr>
<th scope="col">Order</th>
<th scope="col">Customer</th>
<th scope="col">Total</th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="3" class="text-center py-6"><div class="spinner-border spinner-border-sm text-secondary me-2" aria-hidden="true"></div><span role="status">Loading orders...</span></td>
</tr>
</tbody>
</table>
</div>15Alert with spinner
An info alert reporting a background sync.
<div class="alert alert-info flex items-center gap-2 mb-0" role="alert">
<div class="spinner-border spinner-border-sm" aria-hidden="true">
</div>
<div>
Syncing 84 projects with the server...
</div>
</div>16Section loader
A large grow spinner with a message, centered in an empty area.
Preparing your experience
This only takes a moment.
<div class="flex flex-col items-center justify-center bg-surface-3 rounded-md py-12">
<div class="spinner-grow text-primary-ink" role="status" style="width: 3.5rem; height: 3.5rem;">
<span class="sr-only">Loading...</span>
</div>
<p class="mt-4 mb-0 font-semibold">Preparing your experience</p>
<p class="small text-muted mb-0">This only takes a moment.</p>
</div>17Typing dots
Three small grow spinners with staggered delays look like a chat typing indicator.
<div class="inline-flex items-center gap-1 bg-surface-3 rounded-full px-4 py-2" role="status">
<span class="spinner-grow spinner-grow-sm text-secondary" style="width:.5rem;height:.5rem" aria-hidden="true"></span><span class="spinner-grow spinner-grow-sm text-secondary" style="width:.5rem;height:.5rem;animation-delay:.2s" aria-hidden="true"></span><span class="spinner-grow spinner-grow-sm text-secondary" style="width:.5rem;height:.5rem;animation-delay:.4s" aria-hidden="true"></span><span class="sr-only">Leo is typing</span>
</div>18In badges and tabs
Tiny spinners inside a badge and a nav link mark items still processing.
<div class="flex flex-wrap items-center gap-4">
<span class="badge text-bg-warning inline-flex items-center gap-1"><span class="spinner-border" style="width:.7rem;height:.7rem;--ui-spinner-border-width:2px" aria-hidden="true"></span>Processing</span>
<ul class="nav nav-tabs">
<li class="nav-item"><a class="nav-link active" aria-current="page" href="#">Ready</a></li>
<li class="nav-item"><a class="nav-link" href="#">Exports <span class="spinner-border spinner-border-sm ms-1" aria-hidden="true"></span></a></li>
</ul>
</div>19Upload dialog
A static dialog card with a spinner, file name and cancel button.
Uploading journey-90.pdf
Please keep this window open.
<div class="card shadow-sm text-center mx-auto" style="max-width:320px">
<div class="card-body p-6">
<div class="spinner-border text-primary-ink mb-4" style="width:2.5rem;height:2.5rem" aria-hidden="true">
</div>
<h3 class="h6" role="status">Uploading journey-90.pdf</h3>
<p class="small text-muted">Please keep this window open.</p>
<button type="button" class="btn btn-sm btn-outline-secondary">Cancel</button>
</div>
</div>20Spinner with progress
A spinner for activity plus a bar for the amount done.
<div class="border rounded-md p-4" style="max-width:420px">
<div class="flex items-center gap-2 mb-2">
<span class="spinner-border spinner-border-sm text-primary-ink" aria-hidden="true"></span><span class="small font-semibold" role="status">Downloading update</span><span class="small text-muted ms-auto">56%</span>
</div>
<div class="progress" role="progressbar" aria-label="Download" aria-valuenow="56" aria-valuemin="0" aria-valuemax="100" style="height:6px">
<div class="progress-bar" style="width: 56%">
</div>
</div>
</div>