Bootstrap Toggle Switch: 16 Examples of Switches and Toggles

Bootstrap 5 draws its toggle switch with CSS alone. The checkbox underneath holds the on/off state, and .form-switch on its wrapper changes how it looks. Bootstrap 4 used .custom-switch, and the Bootstrap 6 alpha, released October 8, 2026, moves to a .switch wrapper.

Below are 16 Bootstrap toggle switch examples you can copy, followed by a guide to the markup, sizing, color, accessibility and version changes.

By Bogdan Sandu ยท Updated October 29, 2026

Every example runs on Bootstrap 5.3.8 from the jsDelivr CDN. Add these tags to your page, then paste an example's HTML, CSS and JS.

<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous">
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.13.2/font/bootstrap-icons.min.css" rel="stylesheet" integrity="sha384-nWN3KqaaVcbEsCjLSV+2jMjh62Iny/+mN3srM8TZeM8N6aj7eDl5wwYggjAJ4/sJ" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js" integrity="sha384-FKyoEForCGlyvwx9Hj09JcYn3nv7wiPVlz7YYwJrWVcXK/BmnVDxM+D2scQbITxI" crossorigin="anonymous"></script>

Switches in settings screens

The form-switch pattern where it earns its keep: settings that apply the moment they change, with live status text, loading states, revealed fields and a confirm step for risky changes.

Notification and privacy settings list

  • form-switch
  • form-check-reverse
  • list-group-flush
  • fieldset

Flip a switch by clicking it or its label.

Two fieldsets of switches inside a flush list group, each switch moved to the right edge with form-check-reverse and described with aria-describedby. The custom CSS enlarges the track, aligns the help text and darkens the unchecked border and thumb so the off state stays visible. A short role="status" line confirms every change.

View code
<div class="card border-0 shadow-sm bsw-settings">
  <div class="card-body px-4 pt-4 pb-2">
    <h3 class="h5 mb-1">Notifications and privacy</h3>
    <p class="small text-body-secondary mb-0">Changes save as soon as you flip a switch.</p>
  </div>
  <fieldset>
    <legend class="fs-6 fw-semibold px-4 pt-3 mb-1">Notifications</legend>
    <div class="list-group list-group-flush">
      <div class="list-group-item px-4 py-3">
        <div class="form-check form-switch form-check-reverse">
          <input class="form-check-input" type="checkbox" role="switch" id="bsw-n-digest" checked aria-describedby="bsw-n-digest-help">
          <label class="form-check-label fw-medium" for="bsw-n-digest">Weekly email digest</label>
          <div class="small text-body-secondary" id="bsw-n-digest-help">A Monday summary of activity in your workspaces.</div>
        </div>
      </div>
      <div class="list-group-item px-4 py-3">
        <div class="form-check form-switch form-check-reverse">
          <input class="form-check-input" type="checkbox" role="switch" id="bsw-n-mentions" checked aria-describedby="bsw-n-mentions-help">
          <label class="form-check-label fw-medium" for="bsw-n-mentions">Push alerts for mentions</label>
          <div class="small text-body-secondary" id="bsw-n-mentions-help">Sent to the mobile app when someone tags you.</div>
        </div>
      </div>
    </div>
  </fieldset>
  <fieldset>
    <legend class="fs-6 fw-semibold px-4 pt-3 mb-1">Privacy</legend>
    <div class="list-group list-group-flush">
      <div class="list-group-item px-4 py-3">
        <div class="form-check form-switch form-check-reverse">
          <input class="form-check-input" type="checkbox" role="switch" id="bsw-p-search" aria-describedby="bsw-p-search-help">
          <label class="form-check-label fw-medium" for="bsw-p-search">Show my profile in search</label>
          <div class="small text-body-secondary" id="bsw-p-search-help">People outside your team can find you by name.</div>
        </div>
      </div>
      <div class="list-group-item px-4 py-3">
        <div class="form-check form-switch form-check-reverse">
          <input class="form-check-input" type="checkbox" role="switch" id="bsw-p-receipts" checked aria-describedby="bsw-p-receipts-help">
          <label class="form-check-label fw-medium" for="bsw-p-receipts">Read receipts</label>
          <div class="small text-body-secondary" id="bsw-p-receipts-help">Others see when you have read their messages.</div>
        </div>
      </div>
    </div>
  </fieldset>
  <p class="small text-success px-4 py-3 mb-0 border-top" id="bsw-n-status" role="status">All settings saved.</p>
</div>

Switch with On and Off words

  • form-switch
  • role="switch"
  • aria-describedby
  • role="status"

Flip a switch by clicking it or its label.

The label stays "Auto-renew" in both states, as the ARIA guide asks, while Off and On words on either side of the track highlight the current state. The words are aria-hidden because role="switch" already announces on or off, and the renewal note under the switch is rewritten on every change and read out through aria-describedby and role="status".

View code
<div class="card border-0 shadow-sm bsw-renew">
  <div class="card-body p-4">
    <h3 class="h6 mb-1">Pro plan</h3>
    <p class="small text-body-secondary mb-0">$96 per year, 5 seats</p>
    <hr>
    <div class="d-flex align-items-center justify-content-between gap-3">
      <label class="form-check-label fw-semibold" for="bsw-renew">Auto-renew</label>
      <div class="form-check form-switch d-flex align-items-center gap-2 m-0 p-0">
        <span class="bsw-word" id="bsw-renew-off" aria-hidden="true">Off</span>
        <input class="form-check-input" type="checkbox" role="switch" id="bsw-renew" checked aria-describedby="bsw-renew-note">
        <span class="bsw-word is-active" id="bsw-renew-on" aria-hidden="true">On</span>
      </div>
    </div>
    <p class="small text-body-secondary mt-3 mb-0" id="bsw-renew-note" role="status">Renews on 29 November 2026. We email you a reminder 7 days before.</p>
  </div>
</div>

Loading and disabled switches

  • disabled
  • spinner-border-sm
  • form-text
  • role="status"

Flip Sync photos, then Sync documents.

Flipping a sync switch disables it and shows a small spinner-border while a fake save runs, then re-enables it, restores focus and reports the result. The two locked rows use the plain disabled attribute, which Bootstrap dims to 0.5 opacity, with form-text explaining why they are locked. The CSS keeps the label readable while a save is in progress.

View code
<div class="card border-0 shadow-sm bsw-busy">
  <div class="card-body p-4">
    <h3 class="h6 mb-3">Cloud sync</h3>
    <div class="form-check form-switch mb-2">
      <input class="form-check-input bsw-busy-input" type="checkbox" role="switch" id="bsw-sync-photos">
      <label class="form-check-label" for="bsw-sync-photos">Sync photos</label>
      <span class="spinner-border spinner-border-sm text-primary ms-2 d-none" aria-hidden="true"></span>
    </div>
    <div class="form-check form-switch mb-3">
      <input class="form-check-input bsw-busy-input" type="checkbox" role="switch" id="bsw-sync-docs" checked>
      <label class="form-check-label" for="bsw-sync-docs">Sync documents</label>
      <span class="spinner-border spinner-border-sm text-primary ms-2 d-none" aria-hidden="true"></span>
    </div>
    <div class="form-check form-switch mb-2">
      <input class="form-check-input" type="checkbox" role="switch" id="bsw-sync-backup" checked disabled aria-describedby="bsw-sync-backup-help">
      <label class="form-check-label" for="bsw-sync-backup">Nightly backup</label>
      <div class="form-text mt-0" id="bsw-sync-backup-help">Managed by your workspace admin.</div>
    </div>
    <div class="form-check form-switch mb-0">
      <input class="form-check-input" type="checkbox" role="switch" id="bsw-sync-mobile" disabled aria-describedby="bsw-sync-mobile-help">
      <label class="form-check-label" for="bsw-sync-mobile">Sync over mobile data</label>
      <div class="form-text mt-0" id="bsw-sync-mobile-help">Available on the Business plan.</div>
    </div>
    <p class="small text-body-secondary border-top pt-3 mt-3 mb-0" id="bsw-sync-msg" role="status">All changes saved.</p>
  </div>
</div>

Switch that reveals extra fields

  • form-switch
  • collapse
  • bootstrap.Collapse
  • aria-controls

Flip a switch by clicking it or its label.

A gift switch that opens a collapse with the recipient name, a message and a second switch. The Collapse instance is created with toggle: false and driven from the change event with show() and hide(), so the panel always matches the switch, and aria-controls points the switch at the panel. The rose accent only touches the checked and focus states.

View code
<div class="card border-0 shadow-sm bsw-gift">
  <div class="card-body p-4">
    <h3 class="h6 mb-1">Delivery options</h3>
    <p class="small text-body-secondary mb-3">Order 4821, arriving Thursday</p>
    <div class="form-check form-switch mb-0">
      <input class="form-check-input" type="checkbox" role="switch" id="bsw-gift" aria-controls="bsw-gift-fields">
      <label class="form-check-label fw-medium" for="bsw-gift">This order is a gift</label>
    </div>
    <div class="collapse" id="bsw-gift-fields">
      <div class="pt-3">
        <div class="mb-3">
          <label class="form-label small fw-semibold" for="bsw-gift-to">Recipient name</label>
          <input class="form-control" type="text" id="bsw-gift-to" autocomplete="off" placeholder="Maya Lindqvist">
        </div>
        <div class="mb-3">
          <label class="form-label small fw-semibold" for="bsw-gift-msg">Gift message</label>
          <textarea class="form-control" id="bsw-gift-msg" rows="2" maxlength="140" placeholder="Happy birthday from all of us"></textarea>
        </div>
        <div class="form-check form-switch mb-0">
          <input class="form-check-input" type="checkbox" role="switch" id="bsw-gift-prices" checked>
          <label class="form-check-label" for="bsw-gift-prices">Hide prices on the packing slip</label>
        </div>
      </div>
    </div>
  </div>
</div>

Confirm before turning a switch off

  • form-switch
  • modal
  • bootstrap.Modal
  • hidden.bs.modal

Turn the switch off to open the confirmation.

Turning off two-step verification is risky, so the change handler puts the switch back on and opens a Bootstrap modal instead. Only the Turn off button commits the change; Cancel, Escape and the close button leave it on. The hidden.bs.modal listener applies the result and returns focus to the switch.

View code
<div class="card border-0 shadow-sm bsw-security">
  <div class="card-body p-4">
    <h3 class="h6 mb-1">Account security</h3>
    <p class="small text-body-secondary mb-3">Signed in as dana@example.com</p>
    <div class="form-check form-switch mb-0">
      <input class="form-check-input" type="checkbox" role="switch" id="bsw-2fa" checked aria-describedby="bsw-2fa-help">
      <label class="form-check-label fw-medium" for="bsw-2fa">Two-step verification</label>
      <div class="small text-body-secondary" id="bsw-2fa-help">A code from your authenticator app is required at sign-in.</div>
    </div>
    <p class="small fw-medium mt-3 mb-0" id="bsw-2fa-status" role="status"></p>
  </div>
</div>
<div class="modal fade" id="bsw-2fa-modal" tabindex="-1" aria-labelledby="bsw-2fa-title" aria-hidden="true">
  <div class="modal-dialog modal-dialog-centered">
    <div class="modal-content">
      <div class="modal-header">
        <h2 class="modal-title fs-5" id="bsw-2fa-title">Turn off two-step verification?</h2>
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
      </div>
      <div class="modal-body">
        <p class="mb-0">Anyone who learns your password could then sign in. You can turn it back on at any time.</p>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Keep it on</button>
        <button type="button" class="btn btn-danger" id="bsw-2fa-off">Turn off</button>
      </div>
    </div>
  </div>
</div>

Size, color, icons and text in the track

The 5.3 switch is sized in em and draws its thumb from the --bs-form-switch-bg variable, so font-size, a few color properties and an absolutely placed layer cover most custom looks without Sass or a plugin.

Small to extra large switches

  • form-switch
  • font-size
  • em sizing
  • d-flex

Flip a few switches to see both states.

Bootstrap 5.3 has no switch size classes, but the input is sized in em (2em by 1em), so a font-size on the input scales the track and thumb together. A flex row replaces the default padding and negative margin, which would not grow with the input, so the label stays centered at every size.

View code
<div class="card border-0 shadow-sm bsw-sizes">
  <div class="card-body p-4 d-grid gap-3">
    <div class="form-check form-switch bsw-size bsw-size-sm">
      <input class="form-check-input" type="checkbox" role="switch" id="bsw-size-sm" checked>
      <label class="form-check-label" for="bsw-size-sm"><span class="d-block fw-medium">Small</span><span class="d-block small text-body-secondary">0.875rem, for dense tables</span></label>
    </div>
    <div class="form-check form-switch bsw-size">
      <input class="form-check-input" type="checkbox" role="switch" id="bsw-size-md">
      <label class="form-check-label" for="bsw-size-md"><span class="d-block fw-medium">Default</span><span class="d-block small text-body-secondary">1rem, 32 by 16 pixels</span></label>
    </div>
    <div class="form-check form-switch bsw-size bsw-size-lg">
      <input class="form-check-input" type="checkbox" role="switch" id="bsw-size-lg" checked>
      <label class="form-check-label" for="bsw-size-lg"><span class="d-block fw-medium">Large</span><span class="d-block small text-body-secondary">1.5rem, for touch screens</span></label>
    </div>
    <div class="form-check form-switch bsw-size bsw-size-xl">
      <input class="form-check-input" type="checkbox" role="switch" id="bsw-size-xl">
      <label class="form-check-label" for="bsw-size-xl"><span class="d-block fw-medium">Extra large</span><span class="d-block small text-body-secondary">2.25rem, for kiosks and TV apps</span></label>
    </div>
  </div>
</div>

Custom colored switches

  • form-switch
  • :checked
  • --bs-form-switch-bg
  • CSS variables

Flip a few switches to see both states.

Each wrapper sets a --bsw-tone variable, and one rule paints the checked track, the focus border and the focus ring from it. The amber switch also swaps --bs-form-switch-bg for a dark thumb, because a white thumb on amber is hard to see. The unchecked thumb and border are darkened from the 25% black default.

View code
<div class="card border-0 shadow-sm bsw-colors">
  <div class="card-body p-4">
    <h3 class="h6 mb-1">Board labels</h3>
    <p class="small text-body-secondary mb-3">Choose which labels show on cards.</p>
    <div class="form-check form-switch bsw-tone bsw-tone-teal mb-2">
      <input class="form-check-input" type="checkbox" role="switch" id="bsw-c-review" checked>
      <label class="form-check-label" for="bsw-c-review">Design review</label>
    </div>
    <div class="form-check form-switch bsw-tone bsw-tone-amber mb-2">
      <input class="form-check-input" type="checkbox" role="switch" id="bsw-c-client" checked>
      <label class="form-check-label" for="bsw-c-client">Waiting on client</label>
    </div>
    <div class="form-check form-switch bsw-tone bsw-tone-rose mb-2">
      <input class="form-check-input" type="checkbox" role="switch" id="bsw-c-blocked">
      <label class="form-check-label" for="bsw-c-blocked">Blocked</label>
    </div>
    <div class="form-check form-switch bsw-tone bsw-tone-violet mb-0">
      <input class="form-check-input" type="checkbox" role="switch" id="bsw-c-research" checked>
      <label class="form-check-label" for="bsw-c-research">Research</label>
    </div>
  </div>
</div>

Quick settings with icons in the track

  • form-switch
  • Bootstrap Icons
  • aria-hidden
  • position-absolute

Flip a few switches to see both states.

Bootstrap Icons sit in an aria-hidden layer placed over the enlarged track with pointer-events: none, so clicks still reach the input. The on icon shows on the left when the thumb moves right, the off icon on the right when it sits left, switched with the :checked sibling selector. The label alone names each setting.

View code
<div class="card border-0 shadow-sm bsw-quick">
  <div class="card-body p-4 d-grid gap-3">
    <div class="form-check form-switch bsw-ico">
      <input class="form-check-input" type="checkbox" role="switch" id="bsw-q-wifi" checked>
      <span class="bsw-ico-track" aria-hidden="true"><i class="bi bi-wifi bsw-ico-on"></i><i class="bi bi-wifi-off bsw-ico-off"></i></span>
      <label class="form-check-label fw-medium" for="bsw-q-wifi">Wi-Fi</label>
    </div>
    <div class="form-check form-switch bsw-ico">
      <input class="form-check-input" type="checkbox" role="switch" id="bsw-q-plane">
      <span class="bsw-ico-track" aria-hidden="true"><i class="bi bi-airplane-fill bsw-ico-on"></i><i class="bi bi-airplane bsw-ico-off"></i></span>
      <label class="form-check-label fw-medium" for="bsw-q-plane">Airplane mode</label>
    </div>
    <div class="form-check form-switch bsw-ico">
      <input class="form-check-input" type="checkbox" role="switch" id="bsw-q-dnd">
      <span class="bsw-ico-track" aria-hidden="true"><i class="bi bi-moon-stars-fill bsw-ico-on"></i><i class="bi bi-moon bsw-ico-off"></i></span>
      <label class="form-check-label fw-medium" for="bsw-q-dnd">Do not disturb</label>
    </div>
  </div>
</div>

On and Off text inside the track

  • form-switch
  • width override
  • aria-hidden
  • no plugin

Flip a few switches to see both states.

The plugin feature people install bootstrap4-toggle for, done in CSS: the input gets a wider track (2.75em) and an aria-hidden layer prints On or Off in the empty half. role="switch" does the announcing, so the visible words are decoration only. The green and slate colors keep both words above 4.5:1.

View code
<div class="card border-0 shadow-sm bsw-store">
  <div class="card-body p-4">
    <h3 class="h6 mb-1">Store status</h3>
    <p class="small text-body-secondary mb-3">Harbor and Pine, online shop</p>
    <div class="d-grid gap-3">
      <div class="form-check form-switch bsw-txt">
        <input class="form-check-input" type="checkbox" role="switch" id="bsw-t-orders" checked>
        <span class="bsw-txt-track" aria-hidden="true"><span class="bsw-txt-on">On</span><span class="bsw-txt-off">Off</span></span>
        <label class="form-check-label" for="bsw-t-orders">Accept new orders</label>
      </div>
      <div class="form-check form-switch bsw-txt">
        <input class="form-check-input" type="checkbox" role="switch" id="bsw-t-guest" checked>
        <span class="bsw-txt-track" aria-hidden="true"><span class="bsw-txt-on">On</span><span class="bsw-txt-off">Off</span></span>
        <label class="form-check-label" for="bsw-t-guest">Guest checkout</label>
      </div>
      <div class="form-check form-switch bsw-txt">
        <input class="form-check-input" type="checkbox" role="switch" id="bsw-t-maint">
        <span class="bsw-txt-track" aria-hidden="true"><span class="bsw-txt-on">On</span><span class="bsw-txt-off">Off</span></span>
        <label class="form-check-label" for="bsw-t-maint">Maintenance mode</label>
      </div>
    </div>
  </div>
</div>

Toggle buttons and segmented controls

When an on/off choice reads better as a button or a set of options: the button plugin with aria-pressed, btn-check checkboxes and radios in a btn-group, and a billing switch that rewrites a pricing table.

Editor toolbar with pressed buttons

  • data-bs-toggle="button"
  • aria-pressed
  • btn-group
  • role="toolbar"

Click the buttons and options.

The button plugin toggles .active and aria-pressed when a button has data-bs-toggle="button", so screen readers hear "pressed" instead of "checked". A document click listener, which runs after the plugin, reads aria-pressed and applies the matching utility class to the sample text. The slate theme is set through --bs-btn-* variables on a prefixed class.

View code
<div class="card border-0 shadow-sm bsw-editor">
  <div class="d-flex flex-wrap gap-2 p-2 border-bottom" role="toolbar" aria-label="Text formatting">
    <div class="btn-group" role="group" aria-label="Font style">
      <button type="button" class="btn bsw-fmt" data-bs-toggle="button" aria-pressed="false" aria-label="Bold" data-bsw-fmt="fw-bold"><i class="bi bi-type-bold" aria-hidden="true"></i></button>
      <button type="button" class="btn bsw-fmt" data-bs-toggle="button" aria-pressed="false" aria-label="Italic" data-bsw-fmt="fst-italic"><i class="bi bi-type-italic" aria-hidden="true"></i></button>
      <button type="button" class="btn bsw-fmt" data-bs-toggle="button" aria-pressed="false" aria-label="Underline" data-bsw-fmt="text-decoration-underline"><i class="bi bi-type-underline" aria-hidden="true"></i></button>
    </div>
    <button type="button" class="btn bsw-fmt active" data-bs-toggle="button" aria-pressed="true" data-bsw-fmt="bsw-serif"><i class="bi bi-fonts me-1" aria-hidden="true"></i>Serif</button>
  </div>
  <p class="p-4 mb-0 bsw-sample bsw-serif" id="bsw-ed-text">Morning light settled over the harbor while the ferry crew checked the ropes one last time.</p>
</div>

Segmented controls with radio buttons

  • btn-group
  • btn-check
  • type="radio"
  • fieldset

Click the buttons and options.

When a setting has a third option, a switch no longer fits. Radio inputs with .btn-check inside a full-width btn-group give a segmented control that arrow keys move through, grouped by a fieldset and legend. The indigo theme comes from --bs-btn-* variables, and the help line under each group updates from a data attribute.

View code
<div class="card border-0 shadow-sm bsw-sync">
  <div class="card-body p-4">
    <fieldset class="mb-4">
      <legend class="fs-6 fw-semibold mb-2">Photo backup</legend>
      <div class="btn-group w-100 bsw-seg">
        <input type="radio" class="btn-check" name="bsw-backup" id="bsw-bk-off" value="off" autocomplete="off" data-bsw-target="bsw-bk-note" data-bsw-note="Photos stay on this device only.">
        <label class="btn" for="bsw-bk-off">Off</label>
        <input type="radio" class="btn-check" name="bsw-backup" id="bsw-bk-wifi" value="wifi" autocomplete="off" checked data-bsw-target="bsw-bk-note" data-bsw-note="Photos upload when you are on Wi-Fi.">
        <label class="btn" for="bsw-bk-wifi">Wi-Fi only</label>
        <input type="radio" class="btn-check" name="bsw-backup" id="bsw-bk-all" value="always" autocomplete="off" data-bsw-target="bsw-bk-note" data-bsw-note="Photos upload on Wi-Fi and mobile data.">
        <label class="btn" for="bsw-bk-all">Always</label>
      </div>
      <p class="form-text mb-0" id="bsw-bk-note" role="status">Photos upload when you are on Wi-Fi.</p>
    </fieldset>
    <fieldset>
      <legend class="fs-6 fw-semibold mb-2">Battery saver</legend>
      <div class="btn-group w-100 bsw-seg">
        <input type="radio" class="btn-check" name="bsw-battery" id="bsw-bat-on" value="on" autocomplete="off" data-bsw-target="bsw-bat-note" data-bsw-note="Background sync pauses below 20% battery.">
        <label class="btn" for="bsw-bat-on">On</label>
        <input type="radio" class="btn-check" name="bsw-battery" id="bsw-bat-off" value="off" autocomplete="off" checked data-bsw-target="bsw-bat-note" data-bsw-note="Sync runs whenever the app is open.">
        <label class="btn" for="bsw-bat-off">Off</label>
      </div>
      <p class="form-text mb-0" id="bsw-bat-note" role="status">Sync runs whenever the app is open.</p>
    </fieldset>
  </div>
</div>

Monthly or yearly pricing switch

  • form-switch
  • row-cols-md-3
  • card
  • data attributes

Click the buttons and options.

One switch rewrites three pricing cards: each price and billing line keeps both values in data attributes, and the change handler swaps the text. The label says what the switch does, "Bill yearly", so it still reads correctly with on or off appended. Cards stack with row-cols-1 and sit in three columns from the md breakpoint, and the violet accent is applied through --bs-btn-* variables and the checked track.

View code
<div class="bsw-pricing">
  <div class="d-flex flex-wrap align-items-center justify-content-center gap-2 mb-1">
    <div class="form-check form-switch m-0">
      <input class="form-check-input" type="checkbox" role="switch" id="bsw-yearly" aria-describedby="bsw-bill-note">
      <label class="form-check-label fw-semibold" for="bsw-yearly">Bill yearly</label>
    </div>
    <span class="badge rounded-pill bg-success-subtle text-success-emphasis">Save 20%</span>
  </div>
  <p class="small text-body-secondary text-center mb-4" id="bsw-bill-note" role="status">Prices per month, billed monthly.</p>
  <div class="row row-cols-1 row-cols-md-3 g-3">
    <div class="col">
      <div class="card h-100 border-0 shadow-sm">
        <div class="card-body p-4 d-flex flex-column">
          <h3 class="h6 mb-1">Starter</h3>
          <p class="small text-body-secondary mb-3">For freelancers</p>
          <p class="mb-0"><span class="fs-2 fw-bold bsw-price" data-bsw-month="$15" data-bsw-year="$12">$15</span> <span class="text-body-secondary">per month</span></p>
          <p class="small text-body-secondary mb-4 bsw-billed" data-bsw-month="Billed monthly" data-bsw-year="$144 billed once a year">Billed monthly</p>
          <a href="#" class="btn btn-outline-dark mt-auto">Choose Starter</a>
        </div>
      </div>
    </div>
    <div class="col">
      <div class="card h-100 shadow-sm bsw-featured">
        <div class="card-body p-4 d-flex flex-column">
          <h3 class="h6 mb-1">Team <span class="badge bsw-badge ms-1">Popular</span></h3>
          <p class="small text-body-secondary mb-3">Up to 10 people</p>
          <p class="mb-0"><span class="fs-2 fw-bold bsw-price" data-bsw-month="$30" data-bsw-year="$24">$30</span> <span class="text-body-secondary">per month</span></p>
          <p class="small text-body-secondary mb-4 bsw-billed" data-bsw-month="Billed monthly" data-bsw-year="$288 billed once a year">Billed monthly</p>
          <a href="#" class="btn bsw-buy mt-auto">Choose Team</a>
        </div>
      </div>
    </div>
    <div class="col">
      <div class="card h-100 border-0 shadow-sm">
        <div class="card-body p-4 d-flex flex-column">
          <h3 class="h6 mb-1">Studio</h3>
          <p class="small text-body-secondary mb-3">Unlimited projects</p>
          <p class="mb-0"><span class="fs-2 fw-bold bsw-price" data-bsw-month="$60" data-bsw-year="$48">$60</span> <span class="text-body-secondary">per month</span></p>
          <p class="small text-body-secondary mb-4 bsw-billed" data-bsw-month="Billed monthly" data-bsw-year="$576 billed once a year">Billed monthly</p>
          <a href="#" class="btn btn-outline-dark mt-auto">Choose Studio</a>
        </div>
      </div>
    </div>
  </div>
</div>

Smart home tiles with btn-check

  • btn-check
  • type="checkbox"
  • row-cols-2
  • Bootstrap Icons

Click the buttons and options.

Each tile is a .btn-check checkbox with a big label, so it is announced as checked or not checked and toggles with Space. The orange checked state, rounded corners and padding come from --bs-btn-* variables on a prefixed class. The visible On and Off text is aria-hidden to keep the accessible name short, and a role="status" counter totals the devices that are on.

View code
<div class="card border-0 shadow-sm bsw-home">
  <div class="card-body p-4">
    <div class="d-flex justify-content-between align-items-baseline gap-2 mb-3">
      <h3 class="h6 mb-0">Living room</h3>
      <span class="small text-body-secondary" id="bsw-home-count" role="status">2 of 4 on</span>
    </div>
    <div class="row row-cols-2 g-2">
      <div class="col">
        <input type="checkbox" class="btn-check bsw-dev" id="bsw-h-lights" autocomplete="off" checked>
        <label class="btn bsw-tile w-100" for="bsw-h-lights"><i class="bi bi-lightbulb fs-4" aria-hidden="true"></i><span class="d-block fw-semibold mt-2">Lights</span><span class="bsw-tile-state small" aria-hidden="true">On</span></label>
      </div>
      <div class="col">
        <input type="checkbox" class="btn-check bsw-dev" id="bsw-h-heat" autocomplete="off">
        <label class="btn bsw-tile w-100" for="bsw-h-heat"><i class="bi bi-thermometer-half fs-4" aria-hidden="true"></i><span class="d-block fw-semibold mt-2">Heating</span><span class="bsw-tile-state small" aria-hidden="true">Off</span></label>
      </div>
      <div class="col">
        <input type="checkbox" class="btn-check bsw-dev" id="bsw-h-fan" autocomplete="off">
        <label class="btn bsw-tile w-100" for="bsw-h-fan"><i class="bi bi-fan fs-4" aria-hidden="true"></i><span class="d-block fw-semibold mt-2">Ceiling fan</span><span class="bsw-tile-state small" aria-hidden="true">Off</span></label>
      </div>
      <div class="col">
        <input type="checkbox" class="btn-check bsw-dev" id="bsw-h-speaker" autocomplete="off" checked>
        <label class="btn bsw-tile w-100" for="bsw-h-speaker"><i class="bi bi-speaker fs-4" aria-hidden="true"></i><span class="d-block fw-semibold mt-2">Speaker</span><span class="bsw-tile-state small" aria-hidden="true">On</span></label>
      </div>
    </div>
  </div>
</div>

Feature flags, theme switch and dark mode

Switches driving bigger pieces of UI: a feature-flag table with a live count, a theme switch that sets data-bs-theme on a container, and a dark control panel.

Feature flag table with a live count

  • table
  • form-switch
  • role="status"
  • d-sm-table-cell

Flip a switch and watch the rest of the panel react.

A production flag list where each flag name is the label of the switch in the last column, so clicking the name flips it too. The header badge counts enabled flags in a role="status" region, and switched-off rows fade to the secondary text color. The rollout column hides under the sm breakpoint so the table fits a phone without scrolling.

View code
<div class="card border-0 shadow-sm bsw-flags">
  <div class="card-header bg-body d-flex flex-wrap justify-content-between align-items-center gap-2 py-3 px-4">
    <h3 class="h6 mb-0">Feature flags, production</h3>
    <span class="badge rounded-pill bsw-flag-count" id="bsw-flag-count" role="status">3 of 6 enabled</span>
  </div>
  <div class="table-responsive">
    <table class="table align-middle mb-0">
      <caption class="visually-hidden">Feature flags for the production environment</caption>
      <thead>
        <tr><th scope="col" class="ps-4">Flag</th><th scope="col" class="d-none d-sm-table-cell">Rollout</th><th scope="col" class="text-end pe-4">On</th></tr>
      </thead>
      <tbody>
        <tr>
          <td class="ps-4"><label class="d-block fw-medium" for="bsw-f-checkout"><code>new-checkout</code></label><span class="small text-body-secondary">One-page checkout flow</span></td>
          <td class="d-none d-sm-table-cell small">25% of users</td>
          <td class="text-end pe-4"><div class="form-check form-switch m-0"><input class="form-check-input bsw-flag" type="checkbox" role="switch" id="bsw-f-checkout" checked></div></td>
        </tr>
        <tr>
          <td class="ps-4"><label class="d-block fw-medium" for="bsw-f-search"><code>search-v2</code></label><span class="small text-body-secondary">Typo-tolerant product search</span></td>
          <td class="d-none d-sm-table-cell small">Staff only</td>
          <td class="text-end pe-4"><div class="form-check form-switch m-0"><input class="form-check-input bsw-flag" type="checkbox" role="switch" id="bsw-f-search"></div></td>
        </tr>
        <tr>
          <td class="ps-4"><label class="d-block fw-medium" for="bsw-f-gift"><code>gift-cards</code></label><span class="small text-body-secondary">Sell and redeem gift cards</span></td>
          <td class="d-none d-sm-table-cell small">100% of users</td>
          <td class="text-end pe-4"><div class="form-check form-switch m-0"><input class="form-check-input bsw-flag" type="checkbox" role="switch" id="bsw-f-gift" checked></div></td>
        </tr>
        <tr>
          <td class="ps-4"><label class="d-block fw-medium" for="bsw-f-export"><code>bulk-export</code></label><span class="small text-body-secondary">CSV export of all orders</span></td>
          <td class="d-none d-sm-table-cell small">10% of users</td>
          <td class="text-end pe-4"><div class="form-check form-switch m-0"><input class="form-check-input bsw-flag" type="checkbox" role="switch" id="bsw-f-export"></div></td>
        </tr>
        <tr>
          <td class="ps-4"><label class="d-block fw-medium" for="bsw-f-chat"><code>live-chat</code></label><span class="small text-body-secondary">Support chat on order pages</span></td>
          <td class="d-none d-sm-table-cell small">Beta accounts</td>
          <td class="text-end pe-4"><div class="form-check form-switch m-0"><input class="form-check-input bsw-flag" type="checkbox" role="switch" id="bsw-f-chat" checked></div></td>
        </tr>
        <tr>
          <td class="ps-4 border-bottom-0"><label class="d-block fw-medium" for="bsw-f-reviews"><code>photo-reviews</code></label><span class="small text-body-secondary">Photos in product reviews</span></td>
          <td class="d-none d-sm-table-cell small border-bottom-0">0% of users</td>
          <td class="text-end pe-4 border-bottom-0"><div class="form-check form-switch m-0"><input class="form-check-input bsw-flag" type="checkbox" role="switch" id="bsw-f-reviews"></div></td>
        </tr>
      </tbody>
    </table>
  </div>
</div>

Dark mode switch for a container

  • data-bs-theme
  • color modes
  • form-switch
  • aria-controls

Flip a switch and watch the rest of the panel react.

Bootstrap 5.3 color modes work on any element, not only html: the switch sets data-bs-theme to dark or light on the profile card, and every component inside picks up the dark CSS variables. The switch label stays "Dark mode" in both states, and a short status line names the active theme.

View code
<div class="bsw-theme">
  <div class="d-flex flex-wrap align-items-center justify-content-between gap-2 mb-3">
    <div class="form-check form-switch m-0 bsw-theme-toggle">
      <input class="form-check-input" type="checkbox" role="switch" id="bsw-theme-sw" aria-controls="bsw-theme-card">
      <label class="form-check-label fw-semibold" for="bsw-theme-sw"><i class="bi bi-moon-stars me-1" aria-hidden="true"></i>Dark mode</label>
    </div>
    <span class="small text-body-secondary" id="bsw-theme-status" role="status">Light theme</span>
  </div>
  <div class="card shadow-sm bsw-theme-card" id="bsw-theme-card" data-bs-theme="light">
    <div class="card-body p-4">
      <div class="d-flex align-items-center gap-3 mb-3">
        <span class="bsw-avatar rounded-circle d-inline-flex align-items-center justify-content-center fw-semibold" aria-hidden="true">AK</span>
        <div>
          <h3 class="h6 mb-0">Aino Korhonen</h3>
          <p class="small text-body-secondary mb-0">Product designer, Helsinki</p>
        </div>
      </div>
      <label class="form-label small fw-semibold" for="bsw-theme-status-input">Status</label>
      <input class="form-control mb-3" type="text" id="bsw-theme-status-input" value="Reviewing the onboarding flow">
      <ul class="list-group mb-3">
        <li class="list-group-item d-flex justify-content-between align-items-center">Open tasks <span class="badge text-bg-primary rounded-pill">8</span></li>
        <li class="list-group-item d-flex justify-content-between align-items-center">Comments to reply <span class="badge text-bg-secondary rounded-pill">3</span></li>
      </ul>
      <div class="d-flex gap-2">
        <button type="button" class="btn btn-primary">Save profile</button>
        <button type="button" class="btn btn-outline-secondary">Cancel</button>
      </div>
    </div>
  </div>
</div>

Dark stream chat controls

  • data-bs-theme="dark"
  • form-switch
  • form-check-reverse
  • --bs-form-switch-bg

Flip Slow mode, then turn Chat off.

A live-stream chat panel in dark mode. The lime checked track gets a dark thumb through --bs-form-switch-bg, and the unchecked thumb is lightened from the 25% white dark-mode default, which needs a selector as specific as the Bootstrap dark rule. Turning Chat off disables the other switches, and a summary sentence follows every change.

View code
<div class="card border-secondary-subtle shadow bsw-live">
  <div class="card-body p-4">
    <div class="d-flex align-items-center justify-content-between gap-2 mb-3">
      <h3 class="h6 mb-0">Stream chat</h3>
      <span class="badge text-bg-danger">Live</span>
    </div>
    <div class="d-grid gap-3">
      <div class="form-check form-switch form-check-reverse text-start m-0">
        <input class="form-check-input" type="checkbox" role="switch" id="bsw-live-chat" checked>
        <label class="form-check-label fw-medium" for="bsw-live-chat">Chat</label>
      </div>
      <div class="form-check form-switch form-check-reverse text-start m-0">
        <input class="form-check-input bsw-live-opt" type="checkbox" role="switch" id="bsw-live-followers">
        <label class="form-check-label" for="bsw-live-followers">Followers-only chat</label>
      </div>
      <div class="form-check form-switch form-check-reverse text-start m-0">
        <input class="form-check-input bsw-live-opt" type="checkbox" role="switch" id="bsw-live-slow">
        <label class="form-check-label" for="bsw-live-slow">Slow mode, 30 seconds</label>
      </div>
      <div class="form-check form-switch form-check-reverse text-start m-0">
        <input class="form-check-input bsw-live-opt" type="checkbox" role="switch" id="bsw-live-links" checked>
        <label class="form-check-label" for="bsw-live-links">Block links</label>
      </div>
    </div>
    <p class="small text-body-secondary border-top border-secondary-subtle pt-3 mt-3 mb-0" id="bsw-live-sum" role="status">Anyone can chat. Links are blocked.</p>
  </div>
</div>

What is a Bootstrap toggle switch?

Strip away the styling and you’re left with a checkbox input. Put .form-switch on its wrapper and it becomes an on/off switch that needs no JavaScript to render or to flip.

It’s the same styled Bootstrap checkbox used elsewhere in a form, wrapped in .form-check. The switch class only changes how that checkbox draws itself.

The thumb isn’t an element at all. Bootstrap paints it as an SVG circle set as the input’s background image, then slides it with background-position (Bootstrap 5.3.8 compiled CSS, 2025).

A few things get mistaken for it. A .btn-check toggle looks like a button but is still a checkbox, and screen readers announce it as checked or not checked (Bootstrap docs, 2025). Bootstrap Toggle and Bootstrap Switch share the name but are separate plugins built on jQuery, and Bootstrap’s v5 migration guide lists jQuery as dropped. The form itself still submits a plain checkbox, so nothing new is happening at the input level.

The markup and classes below target Bootstrap 5.3.8, the latest 5.3.x release in the docs checked in October 2026.

How to create a Bootstrap toggle switch

Load Bootstrap’s CSS, then wrap a checkbox in a div that carries both .form-check and .form-switch. The label’s for has to match the input id.

  1. Load the CSS by adding the jsDelivr link tag from the Bootstrap download page, or run npm install bootstrap@5.3.8.
  2. Skip the JavaScript bundle unless the page uses other Bootstrap plugins. The switch itself is pure CSS.
  3. Create the wrapper, a div.form-check.form-switch.
  4. Add the input with form-check-input, type="checkbox", role="switch" and a unique id.
  5. Add the label with form-check-label and a matching for.
<div class="form-check form-switch">
  <input class="form-check-input" type="checkbox" role="switch" id="notifySwitch">
  <label class="form-check-label" for="notifySwitch">Email notifications</label>
</div>

Markup structure

The input and label are siblings, not parent and child. Bootstrap styles the label through the sibling selector, and the for and id pair is what connects the two for clicks and screen readers, so every docs example uses it (Bootstrap docs, 2025).

  • .form-check wraps everything as a block with a minimum height
  • .form-switch swaps the square box for a track and thumb
  • .form-check-input is the checkbox itself
  • the label gets .form-check-label, which dims when the input is disabled

Inside a larger Bootstrap form, the switch takes the same wrapper as any other check, so it stacks and spaces like its neighbors.

One mistake to watch for. The selector is .form-switch .form-check-input, so putting .form-switch on the input itself does nothing and the control stays a square box.

Checked, disabled and focus states

Add checked to start in the on position and disabled to lock the control.

StateHow to set itWhat changes
Checkedchecked attributeTrack fills with the primary color, thumb moves right and turns white
Disableddisabled attributeInput and label dim, pointer events stop
Disabled and checkedboth attributesOn position kept, dimmed
FocusTab key or clickThumb turns light blue, focus ring appears

Bootstrap turns off the thumb’s slide transition for visitors who set prefers-reduced-motion (compiled CSS, Bootstrap 5.3.8).

Changing the size, color and label position of a Bootstrap switch

Bootstrap 5.3 handles switch size and color through Sass variables, and label position through two modifier classes. There’s no size class in 5.3, so the default dimensions are the numbers you end up overriding.

The defaults, pulled from the compiled sources:

  • The track is 2em wide, from $form-switch-width (Bootstrap 5.3.8 docs, 2025)
  • The wrapper has 2.5em of left padding (compiled CSS, Bootstrap 5.3.8)
  • Disabled opacity sits at 0.5 on both input and label (compiled CSS, Bootstrap 5.3.8)
  • Bootstrap 6.0.0-alpha.1 defaults to a height of 1.25rem (Bootstrap 6.0 docs)
  • Its default width is 1.75 times the height (Bootstrap 6.0 docs)

Size

On 5.3.8 there’s no size class and no CSS custom property for size. Override $form-switch-width in Sass before the variables import, or set a larger font-size on the .form-switch wrapper so padding, margin and width scale together.

Bootstrap 6.0.0-alpha.1 is friendlier here. It adds .switch-sm and .switch-lg on the wrapper, plus --bs-switch-width and --bs-switch-indicator-width for custom sizes.

Sources disagree on a 5.x size variable. fastbootstrap’s switch page documents --bs-form-switch-width and --bs-form-switch-height, yet the .form-switch rules in the compiled Bootstrap 5.3.8 stylesheet define only --bs-form-switch-bg, so on a stock CDN build those two names do nothing.

Without a Sass build, plain CSS aimed at .form-switch .form-check-input does the same job. The approach to overriding Bootstrap’s default CSS without touching the source files applies here unchanged.

Checked and thumb color

The checked track takes the primary theme color, set by $form-check-input-checked-bg-color. The unchecked thumb comes from $form-switch-color, a translucent black, and the focused thumb from $form-switch-focus-color. Once the switch is on, $form-switch-checked-color takes over, and it’s white by default.

Because the thumb is a background image, color and background-color never reach it. Each state stores its own SVG in --bs-form-switch-bg, and a CSS override has to replace that value state by state.

.form-switch .form-check-input:checked {
  background-color: #198754;
  border-color: #198754;
}

That recolors the track only. The thumb keeps its white fill.

Label position

For a label on the left, add .form-check-reverse to the same element as .form-switch, so the wrapper reads .form-switch.form-check-reverse. A row layout needs .form-check-inline on each wrapper. If there’s no visible text at all, put aria-label on the input.

Bootstrap’s forms documentation still recommends a visible label where possible, for both accessibility and usability (Bootstrap docs, 2025).

How do you read a Bootstrap switch value in JavaScript?

Listen for the change event on the input and read its checked property. It’s true when the switch is on and false when it’s off.

const sw = document.querySelector("#notifySwitch");

sw.addEventListener("change", () => {
  console.log(sw.checked);
});

Per MDN (2025), the change event fires when the user checks or unchecks the box, by click or by keyboard. The whole handler is a few lines of plain JavaScript, and Bootstrap 5 no longer needs jQuery for it.

Attribute versus property matters here. The checked attribute sets only the default state, while the checked property tracks the live one (MDN, 2025). MDN also describes change as a user event, so after setting checked in a script, call your update logic yourself.

The value property is another snag. It holds a string that defaults to “on” when no value attribute is set (MDN, 2026), so read checked to learn the state.

A form behaves differently from a script. MDN states that an unchecked checkbox sends neither its name nor its value, and plain HTML has no way to send an off value (MDN, 2026).

Switch stateMarkupSubmitted data for name=”setting”
Onvalue=”yes”setting=yes
Onno value attributesetting=on
Offanynothing

MDN’s workaround is a hidden input, added by script, that carries the off value.

For a switch that saves a setting the moment it flips, skip the submit and post the new state with an Ajax request from the change handler.

Accessibility requirements for a Bootstrap switch

A switch passes the basics once the input carries role=”switch” and a visible label names the setting. That label shouldn’t name the state, and the Space key has to flip the control.

The ARIA switch role makes screen readers announce on and off instead of checked and unchecked. Bootstrap’s docs say to consider the role and note that older assistive technology falls back to announcing a regular checkbox (Bootstrap docs, 2025).

Keep the label constant. The W3C’s ARIA Authoring Practices Guide (2026) calls it critical that a switch label does not change with its state, so “Email notifications” stays as is whether the control is on or off. Try reading the label aloud with “on” or “off” appended, and rewrite it if it stops making sense (Nielsen Norman Group, 2018).

Space is the key that matters. The guide requires it and lists Enter as optional, and a native checkbox already answers to Space. As for states, MDN documents no mixed state for the switch role, and a mixed aria-checked value is treated as false.

Group related switches in a fieldset with a legend, and point helper text at the input with aria-describedby. The fieldset comes from the guide’s own examples and aria-describedby from the pattern’s list of properties, and both carry over to any accessible forms work on the same page.

There’s also a native switch attribute now. Safari 17.4 shipped <input type="checkbox" switch>, announced in WebKit’s post of February 28, 2024. It uses the ARIA switch role underneath, and browsers without support treat the input as an ordinary checkbox.

Bootstrap’s docs recommend adding it for haptic feedback on iOS 17.4 and later, with no visual change because Bootstrap draws its own switch (Bootstrap docs, 2025).

MDN still labels the attribute experimental with limited browser support (MDN, 2026), so treat it as an enhancement on top of role="switch". Bootstrap 6’s own switch example uses both.

Bootstrap 4, 5 and 6 switch classes compared

Bootstrap 4 builds the switch on .custom-control.custom-switch. Bootstrap 5 uses .form-check.form-switch, and the Bootstrap 6 alpha goes with a .switch wrapper around the input.

ItemBootstrap 4.6Bootstrap 5.3Bootstrap 6 alpha
Wrapper.custom-control .custom-switch.form-check .form-switch.switch
Input.custom-control-input.form-check-inputCheckbox with role="switch" and switch
Label.custom-control-label.form-check-labelPlain label, optionally in .form-field
Thumb drawn byLabel pseudo-elementsInput background imageIndicator under an invisible checkbox
Status, October 2026End of lifeLatest 5.3.xAlpha 1

Bootstrap’s 4.6.2 announcement set end of life for January 1, 2023, and the first Bootstrap 6 alpha followed on October 8, 2026 (Bootstrap blog, 2022 and 2026).

Going from 4 to 5 is mostly renaming. The markup keeps its shape, an input and a sibling label inside one wrapper, and only the class names change. Bootstrap 5 folds the custom-control classes into .form-check and the custom switch into .form-switch (Bootstrap 5 migration guide).

The jump from 5 to 6 is rougher. Version 6 positions the thumb absolutely and styles it through indicator tokens such as --bs-switch-indicator-bg. The migration guide warns that themes overriding the old padding-based behavior need updating, so treat any --bs-form-switch-bg override from version 5 as a rewrite.

Color moves from Sass variables to a class, because .theme-success on the .switch wrapper sets the checked background and border (Bootstrap 6.0 docs).

The .btn-check class from toggle buttons also moves. In version 6 it sits on the label, with the input nested inside it.

Version 6 raises the browser floor to Chrome and Edge 130, Firefox 132 and Safari 18, where version 5 supported Chrome and Firefox 60 and Safari 12 (Bootstrap 6 migration guide).

Below that floor pages do not render correctly, because version 6 ships no fallbacks or polyfills, so treat the move as a cross-browser compatibility call before it is a markup task.

Native switch or plugin: which one should you use?

On Bootstrap 5, use the native .form-switch. A plugin earns its place only when the design needs On and Off text inside the control or the page is stuck on an older Bootstrap.

OptionBootstrap versionsjQueryMain risk
Native .form-switch5.xNoOn/Off text needs custom CSS
bootstrap4-toggle4YesNeeds jQuery, which Bootstrap 5 dropped
Bootstrap Switch2 (no longer official), 3 and 4YesNot documented for Bootstrap 5
bootstrap-switch-button4 and laterUnclearREADME and examples disagree on jQuery
bootstrap5-toggle5OptionalA third-party dependency for a cosmetic feature

Version ranges come from each project’s own pages: the Bootstrap Switch README (v3.4.0), the gitbrent READMEs for bootstrap4-toggle and bootstrap-switch-button, and the bootstrap5-toggle README.

What plugins add is mostly cosmetic. bootstrap4-toggle takes custom on and off text, four sizes (large, normal, small, mini), onstyle and offstyle colors, and on, off, toggle, enable, disable and destroy methods through jQuery (bootstrap4-toggle README).

Both gitbrent READMEs tell you to listen for change on the checkbox itself instead of a plugin event, so the handler pattern from the scripting section stays the same.

bootstrap5-toggle is the Bootstrap 5 successor, version 5.5.0 on npm as of October 2026. It ships one build without jQuery and one with it, and takes the same kind of on and off labels and styles (bootstrap5-toggle README).

bootstrap-switch-button’s README table lists it as Bootstrap 4+ with no dependencies, yet its usage examples call jQuery with $("#chkSwitch").switchbutton(). Test it on a real Bootstrap 5 build before trusting either statement.

Tutorials such as tutorialspoint’s still walk through Bootstrap Toggle 2.2.2 for this job, which adds a plugin where one class would do on Bootstrap 5. If the design needs text inside the track, a hand-built CSS toggle switch avoids both the plugin and jQuery.

When a toggle switch is the wrong control

Use a checkbox instead when a change needs a Save or Submit button, because a switch promises an immediate effect.

Nielsen Norman Group (2018) warns against placing toggles in long forms where other fields wait for Submit, since users cannot tell whether the toggle already applied. That doubt is a usability problem a plain checkbox avoids.

In the United Airlines iOS app, tapping a toggle changed its look and nothing else, and NN/g judged a single checkbox the better fit.

  • Picking several items from a list calls for checkboxes, since a toggle covers exactly one option (NN/g)
  • Picking one item from several calls for radio buttons
  • A select-all parent that shows partial selection needs a checkbox, because the switch role has no mixed state (MDN) and :indeterminate never matches a switch (WebKit)
  • Changes that only apply after an Apply button should use a checkbox too

NN/g, WebKit and the W3C guide each reach the same test from a different direction. NN/g asks whether the change is immediate. WebKit wants to know if users read the control as a setting that is on or off, and the W3C guide’s question is whether on and off or checked and unchecked reads better to a screen reader user.

Bootstrap ships no save logic for a switch, so the immediate effect is your handler’s job. If the request fails, put the switch back and say so, because a control that flips and does nothing is the failure NN/g flagged in the airline app.

Bootstrap Toggle Switch FAQ

Can a Bootstrap switch show On and Off text inside the track?

Not through a built-in option in Bootstrap 5.3. A plugin such as bootstrap5-toggle accepts custom on and off text (bootstrap4-toggle does the same on Bootstrap 4), or custom CSS can add it.

Show both words, because Nielsen Norman Group (2018) warns that a lone descriptor beside the control reads as its label.

Does a Bootstrap switch work in dark mode?

Yes. Bootstrap 5.3.0 added color modes, and data-bs-theme="dark" on the html element or on a single wrapper switches the control (Bootstrap docs, 2025).

The dark thumb has its own Sass variable, $form-switch-color-dark, so a custom thumb color needs a dark counterpart.

How do I add a Bootstrap switch in React?

Render Form.Check with type="switch", an id and a label, or use the Form.Switch alias that wraps it (React-Bootstrap docs, 2026).

The v2 line (latest stable release 2.10.10) targets Bootstrap 5, and v3 is still in beta (3.0.0-beta.6) and also targets Bootstrap 5. The v1.x line targets Bootstrap 4 and is no longer maintained.

Which Vue library works with Bootstrap 5 switches?

BootstrapVueNext. Its docs describe an entirely new implementation on Vue 3 and Bootstrap 5, so it is not a drop-in replacement.

The original BootstrapVue stays on Vue 2 and Bootstrap 4.

Why does my Bootstrap switch render as a plain checkbox?

Usually a version mismatch. The wrapper classes differ in every release, so custom-switch markup has no effect on a Bootstrap 5.3 stylesheet, and form-switch has none on 4.6.

Check which CSS file the page loads before editing the markup.

Should New Projects Start on Bootstrap 5.3 or 6?

A new Bootstrap toggle switch should start on Bootstrap 5.3.8 markup with .form-switch, because version 6 is still in alpha.

Bootstrap’s blog announced 5.3.8 as the last patch before v5.4.0, and no 5.4.0 release is listed on npm as of October 29, 2026 (Bootstrap blog, 2025). A 5.4.0 release or an end-of-life notice for version 5 would change this advice.

Bootstrap 4 reached end of life roughly 20 months after Bootstrap 5 became the default on May 5, 2021, a precedent for the migration window.

Markup renames are cheap. Overrides are what break on migration, so browser analytics should settle the timing.

  • Write markup against .form-switch on 5.3.8 and keep every size and color override in one stylesheet
  • Test the browser floor before moving to 6