Skip to content

Documentation

On this page

Buttons

A command is a <button>. A toggle that should persist or submit is a checkbox or radio with .btn-check and a <label class="btn">. There is no data-bs-toggle="button" and no script that sets aria-pressed. A price-toggle recipe that uses this pattern lives on Composed examples.

Sizes are minified and gzip. A plugin figure includes the Bootstrap runtime that plugin imports. Shipping every plugin is bootstrap.bundle.min.js at 23.3 KB gzip, not the sum of these rows.
What runs it JavaScript
Bootstrap 5.3 Button plugin. It toggles .active and aria-pressed on a button. 1.4 KB gzip
This repo checkbox or radio with .btn-check and a label.btn 0 KB
Markup this component accepts. The full inventory is /components.json.
Avoid
  • Do not add data-bs-toggle="button". State is the input’s checked attribute.
  • Do not set aria-pressed on the label. The checkbox or radio is the accessible control.
  • A lone <button> is a command, not a toggle. Use an input when the choice submits or persists.

How it works

  • .btn-check visually hides the input. The label is the hit target and takes the button look. The input stays in the accessibility tree and in the form.
  • Checkbox groups are additive. Radio groups share a name so one choice is exclusive.
  • State is checked. Do not add data-bs-toggle="button" or toggle .active from script.
  • Ordinary .btn command buttons are unchanged. They still use command / commandfor to open a dialog or popover.

Checkbox

Each label is a toggle. Both can stay on.

Notifications
HTML
<fieldset>
  <legend class="visually-hidden">Notifications</legend>
  <input type="checkbox" class="btn-check" id="buttons-email" autocomplete="off" checked>
  <label class="btn btn-outline-primary" for="buttons-email">Email</label>
  <input type="checkbox" class="btn-check" id="buttons-sms" autocomplete="off">
  <label class="btn btn-outline-primary" for="buttons-sms">SMS</label>
</fieldset>

Radio

One name, one selected. The checked label uses the button active look.

Plan
HTML
<fieldset>
  <legend class="visually-hidden">Plan</legend>
  <input type="radio" class="btn-check" name="buttons-plan" id="buttons-monthly" autocomplete="off" checked>
  <label class="btn btn-outline-primary" for="buttons-monthly">Monthly</label>
  <input type="radio" class="btn-check" name="buttons-plan" id="buttons-yearly" autocomplete="off">
  <label class="btn btn-outline-primary" for="buttons-yearly">Yearly</label>
</fieldset>

Accessibility

The input stays in the tree. .btn-check visually hides it; the label is the hit target. Do not add display: none on the input.

Group radios with the same name. A checkbox group can sit in a <fieldset> with a <legend>.

Do not put role="button" on the label. It is already a label for the input.

Browser support

Three columns, not one baseline. The same row is on the overview.
No script Polyfill No fallback
.btn-check is CSS on a native checkbox or radio. Chrome, Firefox, and Safari have shipped it with Bootstrap’s stylesheet. None None. Without this stylesheet the control is still a checkbox or radio. The label just looks like a button when .btn-check is present.