Lesson 5 of 12

Bootstrap Buttons and Badges

Buttons are how people act on a page: submit a form, open a dialog, add something to a cart. Bootstrap buttons give you a clear, consistent look with hover, focus and disabled states already designed. Badges are their small companions, used for counts such as “3 new” and short labels such as “Beta”.

The btn class and colour variants

Every button starts with the base class btn, which sets padding, font, border radius and the focus ring. Add one variant class for the colour: btn-primary, btn-secondary, btn-success, btn-danger, btn-warning, btn-info, btn-light, btn-dark or btn-link (which looks like a link). For a lighter look, use outline variants such as btn-outline-primary.

The btn classes work on <button>, <a> and <input type="submit">. Choose the element by what it does, not how it looks. If it goes to another page, use a link; if it does something on this page (submits, opens, toggles), use a button. Always write type="button" on buttons that are not meant to submit a form, because the default type inside a form is submit.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Button variants and sizes</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
</head>
<body>
<div class="container py-4">
  <h2 class="h6 text-body-secondary">Solid</h2>
  <div class="d-flex flex-wrap gap-2 mb-3">
    <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-dark">Dark</button>
    <button type="button" class="btn btn-link">Link</button>
  </div>

  <h2 class="h6 text-body-secondary">Outline</h2>
  <div class="d-flex flex-wrap gap-2 mb-3">
    <button type="button" class="btn btn-outline-primary">Primary</button>
    <button type="button" class="btn btn-outline-success">Success</button>
    <button type="button" class="btn btn-outline-danger">Danger</button>
  </div>

  <h2 class="h6 text-body-secondary">Sizes and states</h2>
  <div class="d-flex flex-wrap align-items-center gap-2 mb-3">
    <button type="button" class="btn btn-primary btn-lg">Large</button>
    <button type="button" class="btn btn-primary">Default</button>
    <button type="button" class="btn btn-primary btn-sm">Small</button>
    <button type="button" class="btn btn-primary" disabled>Disabled</button>
    <a class="btn btn-outline-secondary disabled" role="button" aria-disabled="true">Disabled link</a>
  </div>

  <h2 class="h6 text-body-secondary">Full-width buttons on phones only</h2>
  <div class="d-grid gap-2 d-md-block">
    <button type="button" class="btn btn-success">Book tickets</button>
    <button type="button" class="btn btn-outline-secondary">Save for later</button>
  </div>
</div>
</body>
</html>

A real <button> is disabled with the disabled attribute. Links have no such attribute, so for a disabled-looking link you add the disabled class, remove the href and add aria-disabled="true" so assistive technology knows it cannot be used.

Bootstrap 5 has no btn-block class. To make Bootstrap buttons full width, wrap them in d-grid gap-2. Adding d-md-block switches back to normal inline buttons from 768px, which is a common pattern: easy-to-tap wide buttons on phones, compact ones on desktops.

Button groups and toggle buttons

Wrap related buttons in btn-group to join them into one bar. Give the group role="group" and an aria-label so screen readers announce what the buttons are for. btn-group-sm and btn-group-lg size the whole group, and btn-group-vertical stacks it.

For choices such as “Veg / Non-veg”, Bootstrap styles real radio buttons and checkboxes to look like buttons. Put the btn-check class on the <input>, then a <label> with button classes right after it. The input is hidden visually but still works with the keyboard and in forms, so you get button looks with proper form behaviour, and no JavaScript is needed.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Button group and radio toggle buttons</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
</head>
<body>
<div class="container py-4">
  <div class="btn-group mb-4" role="group" aria-label="Text alignment">
    <button type="button" class="btn btn-outline-dark">Left</button>
    <button type="button" class="btn btn-outline-dark">Centre</button>
    <button type="button" class="btn btn-outline-dark">Right</button>
  </div>

  <p class="fw-semibold mb-2">Meal preference</p>
  <div class="btn-group" role="group" aria-label="Meal preference">
    <input type="radio" class="btn-check" name="meal" id="meal-veg" value="Vegetarian" autocomplete="off" checked>
    <label class="btn btn-outline-success" for="meal-veg">Vegetarian</label>

    <input type="radio" class="btn-check" name="meal" id="meal-nonveg" value="Non-vegetarian" autocomplete="off">
    <label class="btn btn-outline-success" for="meal-nonveg">Non-vegetarian</label>

    <input type="radio" class="btn-check" name="meal" id="meal-jain" value="Jain" autocomplete="off">
    <label class="btn btn-outline-success" for="meal-jain">Jain</label>
  </div>
  <p class="mt-3" id="choice">You chose: Vegetarian</p>
</div>
<script>
document.querySelectorAll('input[name="meal"]').forEach((input) => {
  input.addEventListener('change', () => {
    document.getElementById('choice').textContent = 'You chose: ' + input.value;
  });
});
</script>
</body>
</html>

Tip: There is also a JavaScript toggle: data-bs-toggle="button" on a single button switches its active class and aria-pressed state on each click. It needs the Bootstrap JavaScript bundle. For choices that are submitted with a form, prefer btn-check inputs.

Badges

A badge is a small inline label made with badge plus a colour, usually text-bg-* so the text stays readable. Badges scale with the surrounding text, so a badge inside an <h3> is bigger than one in a paragraph. Add rounded-pill for a capsule shape (this replaced the Bootstrap 4 class badge-pill).

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Badges for labels and counts</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
</head>
<body>
<div class="container py-4">
  <h2 class="h4">Filter coffee kit <span class="badge text-bg-success">New</span></h2>
  <p>Shipping from Kumbakonam <span class="badge rounded-pill text-bg-secondary">2–4 days</span></p>

  <button type="button" class="btn btn-primary">
    Messages <span class="badge text-bg-light">4</span>
  </button>

  <button type="button" class="btn btn-outline-dark position-relative ms-3">
    Cart
    <span class="position-absolute top-0 start-100 translate-middle badge rounded-pill text-bg-danger">
      3 <span class="visually-hidden">items in cart</span>
    </span>
  </button>

  <p class="mt-4">
    <span class="badge bg-primary-subtle text-primary-emphasis border border-primary-subtle">HTML</span>
    <span class="badge bg-success-subtle text-success-emphasis border border-success-subtle">CSS</span>
    <span class="badge bg-warning-subtle text-warning-emphasis border border-warning-subtle">JavaScript</span>
  </p>
</div>
</body>
</html>

Watch out: A screen reader reads “Cart 3” for the button above unless you add context. Include hidden helper text with visually-hidden, such as “items in cart”, so the number makes sense when heard rather than seen.

Choosing colours and labels

Use the colour of Bootstrap buttons to show the weight of an action. The main action on a screen gets a solid btn-primary. Secondary actions, such as Cancel or Back, get an outline or btn-secondary style so they are clearly less important. Save btn-danger for actions that delete or cannot be undone, so the red colour keeps its warning meaning.

Write button labels as verbs that say what will happen: Book tickets, Download invoice, Send message. Labels like Click here or Submit give no clue about the result. Keep them short so they fit on one line on a phone, and make sure touch targets are comfortably large; btn-lg can help on mobile-first forms.

Customising Bootstrap buttons

All Bootstrap buttons read their colours from CSS variables such as --bs-btn-bg, --bs-btn-color and --bs-btn-hover-bg. You can make a one-off size with an inline style, for example style="--bs-btn-padding-y: .25rem; --bs-btn-font-size: .8rem;", or create your own variant class. Customize Bootstrap and Dark Mode shows this in detail. Keep one primary button per section so people know the main action; too many bright buttons compete for attention.

Further reading

Key takeaways

  • Every button needs btn plus a variant such as btn-primary or btn-outline-danger.
  • Use <button type="button"> for actions and <a> for navigation.
  • Use btn-lg/btn-sm for size and d-grid gap-2 for full-width buttons.
  • Group buttons with btn-group, role="group" and an aria-label; use btn-check for toggle choices.
  • Badges use badge with text-bg-*; add rounded-pill for a capsule and hidden context text for counts.

Quick quiz

Check what you learned – pick an answer.

1. How do you make a full-width button in Bootstrap 5?

2. What is the correct way to show a link styled as a disabled button?

3. Which class replaced Bootstrap 4's badge-pill?

Practice exercise

Build a "Choose your seat class" control for a bus booking page in Chennai using three radio inputs styled as outline buttons (Sleeper, Semi-sleeper, Seater) inside a labelled button group. Below it, add a large green "Continue" button and a "Notifications" button with a red pill badge showing 5.

Show a hint

Use btn-check on each input, btn btn-outline-primary on each label, and badge rounded-pill text-bg-danger.

Show the solution
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Seat class chooser</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
</head>
<body>
<div class="container py-4">
  <p class="fw-semibold mb-2">Choose your seat class</p>
  <div class="btn-group mb-4" role="group" aria-label="Seat class">
    <input type="radio" class="btn-check" name="seat" id="seat-sleeper" autocomplete="off" checked>
    <label class="btn btn-outline-primary" for="seat-sleeper">Sleeper</label>
    <input type="radio" class="btn-check" name="seat" id="seat-semi" autocomplete="off">
    <label class="btn btn-outline-primary" for="seat-semi">Semi-sleeper</label>
    <input type="radio" class="btn-check" name="seat" id="seat-seater" autocomplete="off">
    <label class="btn btn-outline-primary" for="seat-seater">Seater</label>
  </div>
  <div class="d-flex flex-wrap gap-2">
    <button type="button" class="btn btn-success btn-lg">Continue</button>
    <button type="button" class="btn btn-outline-secondary btn-lg">
      Notifications <span class="badge rounded-pill text-bg-danger">5</span>
    </button>
  </div>
</div>
</body>
</html>

Progress is saved in this browser only.