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="visually-hidden">Loading...</span>
</div>2Colored border spinners
Text colour utilities change the spinner colour.
<div class="d-flex flex-wrap gap-2">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<div class="spinner-border text-secondary" 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-border text-danger" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<div class="spinner-border text-warning" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<div class="spinner-border text-info" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<div class="spinner-border text-dark" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>3Grow spinner
A dot that grows and fades instead of spinning.
<div class="spinner-grow" role="status">
<span class="visually-hidden">Loading...</span>
</div>4Colored grow spinners
The grow spinner in every theme colour.
<div class="d-flex flex-wrap gap-2">
<div class="spinner-grow text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<div class="spinner-grow text-secondary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<div class="spinner-grow 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>
<div class="spinner-grow text-warning" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<div class="spinner-grow text-info" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<div class="spinner-grow text-dark" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>5Sizes
<code>.spinner-border-sm</code> / <code>.spinner-grow-sm</code>, or any size through width and height.
<div class="d-flex flex-wrap align-items-center gap-3">
<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>
<div class="spinner-border" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<div class="spinner-border text-primary" role="status" style="width: 3rem; height: 3rem;">
<span class="visually-hidden">Loading...</span>
</div>
<div class="spinner-grow text-primary" role="status" style="width: 3rem; height: 3rem;">
<span class="visually-hidden">Loading...</span>
</div>
</div>6Loading buttons
Disabled buttons with a small spinner while a request runs.
<div class="d-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="visually-hidden" 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="d-flex justify-content-center mb-3">
<div class="spinner-border" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
<div class="d-flex align-items-center border rounded p-2">
<strong role="status">Loading routines...</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="visually-hidden">Loading...</span>
</div>
</div>
<div class="text-center">
<div class="spinner-border spinner-border-sm" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
<div class="text-end">
<div class="spinner-border spinner-border-sm" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>9Card overlay
A translucent overlay with a spinner covers a card that is updating.
<div class="card position-relative overflow-hidden" style="max-width:360px">
<div class="card-body">
<h3 class="h6 card-title">Single sign-on</h3>
<p class="card-text small">Clear prices, honest advice and no surprises along the way.</p>
<a href="#" class="btn btn-sm btn-primary">Open</a>
</div>
<div class="position-absolute top-0 start-0 w-100 h-100 d-flex flex-column align-items-center justify-content-center bg-body" style="--bs-bg-opacity:.75">
<div class="spinner-border text-primary" 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="visually-hidden">Search</label>
<input type="search" class="form-control" id="spin-search-1218" value="plan"><span class="input-group-text"><span class="spinner-border spinner-border-sm text-secondary" role="status"><span class="visually-hidden">Searching...</span></span></span>
</div>11Custom speed
Change the animation speed with <code>--bs-spinner-animation-speed</code>.
<div class="d-flex gap-3 align-items-center">
<div class="spinner-border text-primary" role="status" style="--bs-spinner-animation-speed: .4s">
<span class="visually-hidden">Loading...</span>
</div>
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<div class="spinner-border text-primary" role="status" style="--bs-spinner-animation-speed: 2.5s">
<span class="visually-hidden">Loading...</span>
</div>
<small class="text-body-secondary">fast / default / slow</small>
</div>12Custom thickness
<code>--bs-spinner-border-width</code> makes the ring thinner or bolder.
<div class="d-flex gap-3 align-items-center">
<div class="spinner-border text-success" role="status" style="--bs-spinner-border-width: 1px; width: 2.5rem; height: 2.5rem">
<span class="visually-hidden">Loading...</span>
</div>
<div class="spinner-border text-success" role="status" style="--bs-spinner-border-width: .5em; width: 2.5rem; height: 2.5rem">
<span class="visually-hidden">Loading...</span>
</div>
<div class="spinner-border text-success" role="status" style="--bs-spinner-border-width: 2px; width: 4rem; height: 4rem">
<span class="visually-hidden">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="d-flex align-items-center gap-2 mb-2 text-success"><i class="bi bi-check-circle-fill" aria-hidden="true"></i> Files uploaded</li>
<li class="d-flex align-items-center gap-2 mb-2 text-success"><i class="bi bi-check-circle-fill" aria-hidden="true"></i> Data checked</li>
<li class="d-flex align-items-center gap-2 mb-2"><span class="spinner-border spinner-border-sm text-primary" aria-hidden="true"></span><span role="status">Building preview...</span></li>
<li class="d-flex align-items-center gap-2 text-body-secondary"><i class="bi bi-circle-fill" 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-4"><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 d-flex align-items-center gap-2 mb-0" role="alert">
<div class="spinner-border spinner-border-sm" aria-hidden="true">
</div>
<div>
Syncing 111 launchs with the server...
</div>
</div>16Section loader
A large grow spinner with a message, centered in an empty area.
Preparing your team
This only takes a moment.
<div class="d-flex flex-column align-items-center justify-content-center bg-body-tertiary rounded py-5">
<div class="spinner-grow text-primary" role="status" style="width: 3.5rem; height: 3.5rem;">
<span class="visually-hidden">Loading...</span>
</div>
<p class="mt-3 mb-0 fw-semibold">Preparing your team</p>
<p class="small text-body-secondary 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="d-inline-flex align-items-center gap-1 bg-body-tertiary rounded-pill px-3 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="visually-hidden">Felix is typing</span>
</div>18In badges and tabs
Tiny spinners inside a badge and a nav link mark items still processing.
<div class="d-flex flex-wrap align-items-center gap-3">
<span class="badge text-bg-warning d-inline-flex align-items-center gap-1"><span class="spinner-border" style="width:.7rem;height:.7rem;--bs-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 workflow-34.pdf
Please keep this window open.
<div class="card shadow-sm text-center mx-auto" style="max-width:320px">
<div class="card-body p-4">
<div class="spinner-border text-primary mb-3" style="width:2.5rem;height:2.5rem" aria-hidden="true">
</div>
<h3 class="h6" role="status">Uploading workflow-34.pdf</h3>
<p class="small text-body-secondary">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 p-3" style="max-width:420px">
<div class="d-flex align-items-center gap-2 mb-2">
<span class="spinner-border spinner-border-sm text-primary" aria-hidden="true"></span><span class="small fw-semibold" role="status">Downloading update</span><span class="small text-body-secondary ms-auto">50%</span>
</div>
<div class="progress" role="progressbar" aria-label="Download" aria-valuenow="50" aria-valuemin="0" aria-valuemax="100" style="height:6px">
<div class="progress-bar" style="width: 50%">
</div>
</div>
</div>