Skip to component content

Group related toggle buttons using Bootstrap's native checkbox and radio button-check contract.

Usage

Use grouped .btn-check inputs with matching .btn labels when related button-like choices need a persistent pressed state. Use radio inputs when exactly one item should stay active, and checkbox inputs when multiple items may be pressed at the same time.

Group the controls under one accessible label, keep every item the same size and variant, and make the selected state visible without relying on color alone. Give every icon-only toggle its own accessible label because the icon is not a name.

Toggle Group uses Bootstrap's button-check contract: native inputs hold the state while labels render the button surface. Keep values stable for form submission, and choose a normal Button Group when the controls are actions rather than selectable modes.

Default

Independent checkbox items let more than one stay pressed at once.

Toggle Group
<div class="toggle-group d-inline-flex gap-2" role="group" aria-label="Notification channels">
  <input
          type="checkbox"
          class="btn-check"
          name="notification-channels"
          id="notify-email"
          value="notify-email"
          autocomplete="off" aria-label="Email">
  <label class="btn btn-ghost btn-icon" for="notify-email">
    <i class="lucide lucide-mail" data-icon="inline-start" aria-hidden="true"></i>
  </label>
  <input
          type="checkbox"
          class="btn-check"
          name="notification-channels"
          id="notify-sms"
          value="notify-sms"
          autocomplete="off" aria-label="SMS" checked>
  <label class="btn btn-ghost btn-icon" for="notify-sms">
    <i class="lucide lucide-message-square" data-icon="inline-start" aria-hidden="true"></i>
  </label>
  <input
          type="checkbox"
          class="btn-check"
          name="notification-channels"
          id="notify-push"
          value="notify-push"
          autocomplete="off" aria-label="Push">
  <label class="btn btn-ghost btn-icon" for="notify-push">
    <i class="lucide lucide-bell" data-icon="inline-start" aria-hidden="true"></i>
  </label>
</div>

Outline variant, single selection

Radio items share one name so exactly one method stays pressed.

Toggle Group
<div class="toggle-group d-inline-flex gap-2" role="group" aria-label="Shipment method">
  <input
          type="radio"
          class="btn-check"
          name="shipment-method"
          id="shipment-standard"
          value="shipment-standard"
          autocomplete="off" checked>
  <label class="btn btn-outline-secondary" for="shipment-standard">
    <i class="lucide lucide-package" data-icon="inline-start" aria-hidden="true"></i>
    Standard
  </label>
  <input
          type="radio"
          class="btn-check"
          name="shipment-method"
          id="shipment-express"
          value="shipment-express"
          autocomplete="off">
  <label class="btn btn-outline-secondary" for="shipment-express">
    <i class="lucide lucide-zap" data-icon="inline-start" aria-hidden="true"></i>
    Express
  </label>
  <input
          type="radio"
          class="btn-check"
          name="shipment-method"
          id="shipment-overnight"
          value="shipment-overnight"
          autocomplete="off">
  <label class="btn btn-outline-secondary" for="shipment-overnight">
    <i class="lucide lucide-rocket" data-icon="inline-start" aria-hidden="true"></i>
    Overnight
  </label>
</div>

Sizes

size sets btn-sm/btn-lg directly on each item, the same scale a plain Button uses.

Toggle Group
<div class="d-flex flex-column gap-3 align-items-center">
  <div class="toggle-group d-inline-flex gap-2" role="group" aria-label="Task priority">
    <input
            type="radio"
            class="btn-check"
            name="task-priority-sm"
            id="priority-low-sm"
            value="priority-low-sm"
            autocomplete="off" aria-label="Low priority">
    <label class="btn btn-ghost btn-icon-sm" for="priority-low-sm">
      <i class="lucide lucide-arrow-down" data-icon="inline-start" aria-hidden="true"></i>
    </label>
    <input
            type="radio"
            class="btn-check"
            name="task-priority-sm"
            id="priority-medium-sm"
            value="priority-medium-sm"
            autocomplete="off" aria-label="Medium priority" checked>
    <label class="btn btn-ghost btn-icon-sm" for="priority-medium-sm">
      <i class="lucide lucide-minus" data-icon="inline-start" aria-hidden="true"></i>
    </label>
    <input
            type="radio"
            class="btn-check"
            name="task-priority-sm"
            id="priority-high-sm"
            value="priority-high-sm"
            autocomplete="off" aria-label="High priority">
    <label class="btn btn-ghost btn-icon-sm" for="priority-high-sm">
      <i class="lucide lucide-arrow-up" data-icon="inline-start" aria-hidden="true"></i>
    </label>
  </div>
  <div class="toggle-group d-inline-flex gap-2" role="group" aria-label="Task priority">
    <input
            type="radio"
            class="btn-check"
            name="task-priority-lg"
            id="priority-low-lg"
            value="priority-low-lg"
            autocomplete="off" aria-label="Low priority">
    <label class="btn btn-ghost btn-icon-lg" for="priority-low-lg">
      <i class="lucide lucide-arrow-down" data-icon="inline-start" aria-hidden="true"></i>
    </label>
    <input
            type="radio"
            class="btn-check"
            name="task-priority-lg"
            id="priority-medium-lg"
            value="priority-medium-lg"
            autocomplete="off" aria-label="Medium priority" checked>
    <label class="btn btn-ghost btn-icon-lg" for="priority-medium-lg">
      <i class="lucide lucide-minus" data-icon="inline-start" aria-hidden="true"></i>
    </label>
    <input
            type="radio"
            class="btn-check"
            name="task-priority-lg"
            id="priority-high-lg"
            value="priority-high-lg"
            autocomplete="off" aria-label="High priority">
    <label class="btn btn-ghost btn-icon-lg" for="priority-high-lg">
      <i class="lucide lucide-arrow-up" data-icon="inline-start" aria-hidden="true"></i>
    </label>
  </div>
</div>

Disabled item

A single item can be disabled without affecting its neighbors.

Toggle Group
<div class="toggle-group d-inline-flex gap-2" role="group" aria-label="Notification channels">
  <input
          type="checkbox"
          class="btn-check"
          name="notification-channels-disabled"
          id="notify-email-disabled"
          value="notify-email-disabled"
          autocomplete="off" aria-label="Email">
  <label class="btn btn-ghost btn-icon" for="notify-email-disabled">
    <i class="lucide lucide-mail" data-icon="inline-start" aria-hidden="true"></i>
  </label>
  <input
          type="checkbox"
          class="btn-check"
          name="notification-channels-disabled"
          id="notify-sms-disabled"
          value="notify-sms-disabled"
          autocomplete="off" aria-label="SMS" checked>
  <label class="btn btn-ghost btn-icon" for="notify-sms-disabled">
    <i class="lucide lucide-message-square" data-icon="inline-start" aria-hidden="true"></i>
  </label>
  <input
          type="checkbox"
          class="btn-check"
          name="notification-channels-disabled"
          id="notify-push-disabled"
          value="notify-push-disabled"
          autocomplete="off" aria-label="Push" disabled>
  <label class="btn btn-ghost btn-icon" for="notify-push-disabled">
    <i class="lucide lucide-bell" data-icon="inline-start" aria-hidden="true"></i>
  </label>
</div>

Vertical

vertical=true switches the flex container to a column and applies the shared vertical spacing token.

Toggle Group
<div class="toggle-group d-inline-flex gap-1 flex-column" role="group" aria-label="Approval stage">
  <input
          type="radio"
          class="btn-check"
          name="approval-stage"
          id="approval-draft"
          value="approval-draft"
          autocomplete="off" checked>
  <label class="btn btn-ghost" for="approval-draft">
    <i class="lucide lucide-pencil" data-icon="inline-start" aria-hidden="true"></i>
    Draft
  </label>
  <input
          type="radio"
          class="btn-check"
          name="approval-stage"
          id="approval-review"
          value="approval-review"
          autocomplete="off">
  <label class="btn btn-ghost" for="approval-review">
    <i class="lucide lucide-eye" data-icon="inline-start" aria-hidden="true"></i>
    Review
  </label>
  <input
          type="radio"
          class="btn-check"
          name="approval-stage"
          id="approval-approved"
          value="approval-approved"
          autocomplete="off">
  <label class="btn btn-ghost" for="approval-approved">
    <i class="lucide lucide-circle-check" data-icon="inline-start" aria-hidden="true"></i>
    Approved
  </label>
</div>

RTL

Use the same shipment method options across Arabic and Hebrew RTL examples, with English as the LTR comparison.

<div dir="rtl">
  <div class="toggle-group d-inline-flex gap-2" role="group" aria-label="Shipment method">
    <input
            type="radio"
            class="btn-check"
            name="shipment-method-rtl-arabic"
            id="shipment-standard-rtl-arabic"
            value="shipment-standard-rtl-arabic"
            autocomplete="off" checked>
    <label class="btn btn-outline-secondary" for="shipment-standard-rtl-arabic">
      <i class="lucide lucide-package" data-icon="inline-start" aria-hidden="true"></i>
      قياسي
    </label>
    <input
            type="radio"
            class="btn-check"
            name="shipment-method-rtl-arabic"
            id="shipment-express-rtl-arabic"
            value="shipment-express-rtl-arabic"
            autocomplete="off">
    <label class="btn btn-outline-secondary" for="shipment-express-rtl-arabic">
      <i class="lucide lucide-zap" data-icon="inline-start" aria-hidden="true"></i>
      سريع
    </label>
    <input
            type="radio"
            class="btn-check"
            name="shipment-method-rtl-arabic"
            id="shipment-overnight-rtl-arabic"
            value="shipment-overnight-rtl-arabic"
            autocomplete="off">
    <label class="btn btn-outline-secondary" for="shipment-overnight-rtl-arabic">
      <i class="lucide lucide-rocket" data-icon="inline-start" aria-hidden="true"></i>
      فوري
    </label>
  </div>
</div>
<div dir="rtl">
  <div class="toggle-group d-inline-flex gap-2" role="group" aria-label="Shipment method">
    <input
            type="radio"
            class="btn-check"
            name="shipment-method-rtl-hebrew"
            id="shipment-standard-rtl-hebrew"
            value="shipment-standard-rtl-hebrew"
            autocomplete="off" checked>
    <label class="btn btn-outline-secondary" for="shipment-standard-rtl-hebrew">
      <i class="lucide lucide-package" data-icon="inline-start" aria-hidden="true"></i>
      רגיל
    </label>
    <input
            type="radio"
            class="btn-check"
            name="shipment-method-rtl-hebrew"
            id="shipment-express-rtl-hebrew"
            value="shipment-express-rtl-hebrew"
            autocomplete="off">
    <label class="btn btn-outline-secondary" for="shipment-express-rtl-hebrew">
      <i class="lucide lucide-zap" data-icon="inline-start" aria-hidden="true"></i>
      מהיר
    </label>
    <input
            type="radio"
            class="btn-check"
            name="shipment-method-rtl-hebrew"
            id="shipment-overnight-rtl-hebrew"
            value="shipment-overnight-rtl-hebrew"
            autocomplete="off">
    <label class="btn btn-outline-secondary" for="shipment-overnight-rtl-hebrew">
      <i class="lucide lucide-rocket" data-icon="inline-start" aria-hidden="true"></i>
      דחוף
    </label>
  </div>
</div>
<div dir="ltr">
  <div class="toggle-group d-inline-flex gap-2" role="group" aria-label="Shipment method">
    <input
            type="radio"
            class="btn-check"
            name="shipment-method-rtl-english"
            id="shipment-standard-rtl-english"
            value="shipment-standard-rtl-english"
            autocomplete="off" checked>
    <label class="btn btn-outline-secondary" for="shipment-standard-rtl-english">
      <i class="lucide lucide-package" data-icon="inline-start" aria-hidden="true"></i>
      Standard
    </label>
    <input
            type="radio"
            class="btn-check"
            name="shipment-method-rtl-english"
            id="shipment-express-rtl-english"
            value="shipment-express-rtl-english"
            autocomplete="off">
    <label class="btn btn-outline-secondary" for="shipment-express-rtl-english">
      <i class="lucide lucide-zap" data-icon="inline-start" aria-hidden="true"></i>
      Express
    </label>
    <input
            type="radio"
            class="btn-check"
            name="shipment-method-rtl-english"
            id="shipment-overnight-rtl-english"
            value="shipment-overnight-rtl-english"
            autocomplete="off">
    <label class="btn btn-outline-secondary" for="shipment-overnight-rtl-english">
      <i class="lucide lucide-rocket" data-icon="inline-start" aria-hidden="true"></i>
      Overnight
    </label>
  </div>
</div>

Component reference

Status
Accepted
Runtime
native HTML/CSS
Markup
Moo UI documented extension
Reference

For Bootstrap's source behavior and the shared checkbox/radio toggle button contract, see the Bootstrap Button group documentation.

Settings

Theme
Choose how Moo UI looks on this device.
Sidebar
Choose how the sidebar sits on the page.
Theme Builder
Tune catalog tokens and chart colors for this browser.
Base color
Theme color
Chart color
Heading font
Body font
Radius
Direction
Choose the reading direction. RTL flips the layout live.
Reset

Restore the default appearance.