Buttons
Variants
<div class="d-flex flex-wrap gap-2 p-2">
<button type="button" class="btn btn-primary">Primary</button>
<button type="button" class="btn btn-secondary">Secondary</button>
<button type="button" class="btn btn-success">Success</button>
<button type="button" class="btn btn-danger">Danger</button>
<button type="button" class="btn btn-warning">Warning</button>
<button type="button" class="btn btn-info">Info</button>
<button type="button" class="btn btn-light">Light</button>
<button type="button" class="btn btn-dark">Dark</button>
<button type="button" class="btn btn-link">Link</button>
</div>Every button needs the base class btn, plus one variant. Choose variants by meaning: one primary button for the main action on a screen, danger for destructive actions like Delete, and quieter styles for the rest.
Outline buttons and sizes
<div class="d-flex flex-wrap align-items-center gap-2 p-2">
<button type="button" class="btn btn-outline-primary">Outline</button>
<button type="button" class="btn btn-outline-danger">Outline danger</button>
<button type="button" class="btn btn-primary btn-lg">Large</button>
<button type="button" class="btn btn-primary btn-sm">Small</button>
</div>Links that look like buttons, and buttons that fill the width
<div class="p-2">
<a href="#" class="btn btn-primary" role="button">A link styled as a button</a>
</div>
<div class="d-grid gap-2 p-2" style="max-width: 22rem">
<button type="button" class="btn btn-success">Full width</button>
<button type="button" class="btn btn-outline-secondary">Also full width</button>
</div>
<div class="d-grid d-md-block p-2">
<button type="button" class="btn btn-dark">Full width on phones only</button>
</div>Use an <a> when the button goes somewhere and a <button> when it does something. Wrapping buttons in d-grid stretches them to the full width, and d-md-block switches back to normal width from md up, a common pattern for phones.
Disabled buttons
<div class="d-flex gap-2 p-2">
<button type="button" class="btn btn-primary" disabled>Disabled</button>
<button type="button" class="btn btn-outline-secondary" disabled>Disabled outline</button>
</div>Button groups
<div class="btn-group p-2" role="group" aria-label="Text alignment">
<button type="button" class="btn btn-outline-primary">Left</button>
<button type="button" class="btn btn-outline-primary">Centre</button>
<button type="button" class="btn btn-outline-primary">Right</button>
</div>Toggle buttons
<div class="btn-group p-2" role="group" aria-label="Choose a plan">
<input type="radio" class="btn-check" name="plan" id="monthly" checked>
<label class="btn btn-outline-success" for="monthly">Monthly</label>
<input type="radio" class="btn-check" name="plan" id="yearly">
<label class="btn btn-outline-success" for="yearly">Yearly</label>
</div>
<div class="p-2">
<input type="checkbox" class="btn-check" id="notify">
<label class="btn btn-outline-primary" for="notify">🔔 Notify me</label>
</div>A hidden radio or checkbox with btn-check, plus a <label> styled as a button, gives a toggle button that keeps all the keyboard and form behaviour of the real input. Click them: radios allow one choice, the checkbox toggles.
Spinners and badges
<div class="d-flex flex-wrap gap-2 p-2">
<button class="btn btn-primary" type="button" id="save">Save</button>
<button type="button" class="btn btn-outline-dark">
Messages <span class="badge text-bg-danger">4</span>
</button>
</div>
<script>
document.querySelector("#save").addEventListener("click", (e) => {
const btn = e.currentTarget;
btn.disabled = true;
btn.innerHTML = '<span class="spinner-border spinner-border-sm" aria-hidden="true"></span> Saving...';
setTimeout(() => { btn.disabled = false; btn.textContent = "Saved ✔"; }, 1500);
});
</script>Click Save: the button disables itself and shows a spinner while it works, which stops people clicking twice and tells them something is happening.