Component Library

← Back to gallery

Toggle button

Category: Buttons · Tags: toggle, aria-pressed, toolbar, formatting, state

Quarterly results are ready for review.

How to use it

Use for an on/off option that applies to the current selection or view, such as text formatting or showing grid lines, where the button's label names the option rather than the state. Never change the label when it is pressed (that tells people the opposite); if the label must change, use a plain button instead. For a setting saved to the user's account use the toggle switch, and for one of several exclusive choices use the button group. Wire each button to your real formatting command in place of the preview class.

Accessibility

Each control is a native <button> with aria-pressed, so screen readers announce it as a toggle button that is pressed or not pressed while its name ("Bold", "Italic", "Underline") stays the same; Enter or Space flips it. The buttons sit in a role="group" with an aria-label so they are announced as one set. Pressed buttons are filled and also show a check mark and a thicker border, so the state does not rely on colour alone, and focus shows a 2px outline. Text is #0f172a on #ffffff (17.85:1), #0f172a on the #e2e8f0 hover (14.48:1) and #ffffff on the #1e3a8a pressed fill (10.36:1).

Source (copy-ready)

<div class="dcl-togglebtn">
  <div class="dcl-togglebtn__bar" role="group" aria-label="Text formatting">
    <button type="button" class="dcl-togglebtn__button" aria-pressed="true" data-style="dcl-togglebtn__preview--bold"><span class="dcl-togglebtn__check" aria-hidden="true">&#10003;</span>Bold</button>
    <button type="button" class="dcl-togglebtn__button" aria-pressed="false" data-style="dcl-togglebtn__preview--italic"><span class="dcl-togglebtn__check" aria-hidden="true">&#10003;</span>Italic</button>
    <button type="button" class="dcl-togglebtn__button" aria-pressed="false" data-style="dcl-togglebtn__preview--underline"><span class="dcl-togglebtn__check" aria-hidden="true">&#10003;</span>Underline</button>
  </div>
  <p class="dcl-togglebtn__preview dcl-togglebtn__preview--bold">Quarterly results are ready for review.</p>
</div>
<style>
.dcl-togglebtn { font: inherit; max-width: 100%; color: #0f172a; background-color: #ffffff; }
.dcl-togglebtn__bar { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.dcl-togglebtn__button { display: inline-flex; align-items: center; gap: 0.35rem; min-height: 2.75rem; padding: 0 1rem; border: 1px solid #64748b; border-radius: 0.5rem; cursor: pointer; font: inherit; color: #0f172a; background-color: #ffffff; }
.dcl-togglebtn__button:hover { color: #0f172a; background-color: #e2e8f0; }
.dcl-togglebtn__button:focus-visible { outline: 2px solid #1d4ed8; outline-offset: 2px; }
.dcl-togglebtn__button[aria-pressed="true"] { border: 2px solid #0f172a; font-weight: 700; color: #ffffff; background-color: #1e3a8a; }
.dcl-togglebtn__check { display: none; }
.dcl-togglebtn__button[aria-pressed="true"] .dcl-togglebtn__check { display: inline; }
.dcl-togglebtn__preview { margin: 1rem 0 0; padding: 0.75rem; border: 1px dashed #94a3b8; border-radius: 0.5rem; color: #0f172a; background-color: #ffffff; }
.dcl-togglebtn__preview--bold { font-weight: 700; }
.dcl-togglebtn__preview--italic { font-style: italic; }
.dcl-togglebtn__preview--underline { text-decoration: underline; }
</style>
<script>
(function () {
  document.querySelectorAll(".dcl-togglebtn").forEach(function (root) {
    if (root.dataset.dclBound) { return; }
    root.dataset.dclBound = "true";
    var preview = root.querySelector(".dcl-togglebtn__preview");
    root.querySelectorAll(".dcl-togglebtn__button").forEach(function (button) {
      button.addEventListener("click", function () {
        var pressed = button.getAttribute("aria-pressed") !== "true";
        button.setAttribute("aria-pressed", pressed ? "true" : "false");
        var style = button.getAttribute("data-style");
        if (preview && style) { preview.classList.toggle(style, pressed); }
      });
    });
  });
})();
</script>

Was this useful? Send feedback.