Accessibility pattern · Overlays

Toggletip

A toggletip is a button that shows a note when pressed; a tooltip, by contrast, appears on hover and has no button of its own. The note is written into a live region a moment after the press, so screen readers announce it without anyone going to look for it.

WCAG criteria
6
Keyboard rules
3
Checked with
axe, keyboard and the inspector

Live demo

Try it

Use it with a mouse, a keyboard or a screen reader. The inspector beside it shows what the browser tells assistive technology as you go: focus, state changes and announcements.

Order summary

Items (3)
₹2,450
Delivery
₹49
Festive discount
−₹200
Total
₹2,299

Prices include GST.

The demo works without JavaScript only as far as its HTML does; the inspector needs JavaScript.

Keyboard

Keys it answers to

Every action works without a pointer.

KeyWhat it does
Enter or SpaceOn an info button, shows its note; pressed again, hides it. Opening one note closes any other.
EscapeHides the open note; focus stays on the button.
Tab or ShiftTabMoves on to the next control and hides the note.

Screen readers

What it announces

Written from the roles, names and states in the markup.

WhenExpected announcement
Focus reaches the info buttonMore about delivery charges, button, collapsed
Enter shows the noteExpanded. Delivery is free on orders over ₹2,999. This one is ₹549 short, so a flat ₹49 applies.
Escape hides itCollapsed

These are expected announcements, not recordings. Wording and order differ between screen readers and browsers.

Code

Copy the code

The exact files this demo runs on. The styles are served with a prefix that keeps this site's own styles out of the demo; what you copy is the original.

The markup

<div class="ap-toggletip" data-ap-toggletip>
  <h3 class="ap-toggletip__name">Order summary</h3>
  <dl class="ap-toggletip__rows">
    <div class="ap-toggletip__row">
      <dt>Items <span class="ap-toggletip__qty">(3)</span></dt>
      <dd>₹2,450</dd>
    </div>
    <div class="ap-toggletip__row">
      <dt>
        Delivery
        <span class="ap-toggletip__wrap">
          <button type="button" class="ap-toggletip__btn" id="toggletip-delivery-btn" aria-label="More about delivery charges" aria-expanded="false">
            <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="9"/><path d="M12 11v5"/><path d="M12 7.5h.01"/></svg>
          </button>
          <span class="ap-toggletip__live" role="status">
            <span class="ap-toggletip__bubble" data-ap-note hidden>Delivery is free on orders over ₹2,999. This one is ₹549 short, so a flat ₹49 applies.</span>
          </span>
        </span>
      </dt>
      <dd>₹49</dd>
    </div>
    <div class="ap-toggletip__row">
      <dt>
        Festive discount
        <span class="ap-toggletip__wrap">
          <button type="button" class="ap-toggletip__btn" id="toggletip-discount-btn" aria-label="More about the festive discount" aria-expanded="false">
            <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="9"/><path d="M12 11v5"/><path d="M12 7.5h.01"/></svg>
          </button>
          <span class="ap-toggletip__live" role="status">
            <span class="ap-toggletip__bubble" data-ap-note hidden>Code DIWALI200 takes ₹200 off orders over ₹1,500. It ends on 3 November.</span>
          </span>
        </span>
      </dt>
      <dd class="ap-toggletip__minus">−₹200</dd>
    </div>
    <div class="ap-toggletip__row ap-toggletip__row--total">
      <dt>Total</dt>
      <dd>₹2,299</dd>
    </div>
  </dl>
  <p class="ap-toggletip__note">Prices include GST.</p>
</div>

WCAG 2.2

What it meets

The success criteria this pattern takes care of, and how.

  • 1.1.1 Non-text Content Level A

    Each info icon is a button named for what it explains, such as More about delivery charges, not just Info.

  • 2.1.1 Keyboard Level A

    The note opens with Enter or Space and closes with Escape, the same button or Tab; no pointer is needed.

  • 2.5.8 Target Size (Minimum) Level AA

    The target is the whole 32-pixel button, not just the 18-pixel icon drawn in it, so it clears the 24-pixel minimum.

  • 4.1.2 Name, Role, Value Level A

    The button carries aria-expanded, so its name, role and whether the note is showing are all exposed.

  • 4.1.3 Status Messages Level AA

    The note is written into a role=status region, so it is announced as it appears without moving focus.

  • 1.4.11 Non-text Contrast Level AA

    The info icon and the button's focus ring both clear 3:1 against the card in both themes.

Usage

When to use it

Use it

  • A sentence or two of help beside a figure or a field: why a charge applies, what a term means.
  • Touch screens, where a tooltip cannot be opened at all.

Use something else

  • A label for an icon button: give the button a name, or a tooltip.
  • Help with links, fields or anything to act on: use a popover or a disclosure.
  • Information everyone needs: write it on the page.

Common failures

How it usually goes wrong

  • A tooltip on an info icon

    Hover-only help cannot be opened on a phone or by many keyboard users. A button that toggles the note works for everyone.

  • A note nobody hears

    Showing a hidden element beside the button says nothing to a screen reader user, who has to go hunting for it. The live region announces it.

  • Every icon called Info

    Five buttons all named Info are indistinguishable in a list of buttons. Name each one for the thing it explains.

  • Links inside the note

    A live region reads its content as plain text, and a link in it is hard to reach. Notes with actions belong in a popover.

  • No way to close it from the keyboard

    A note that only an outside click dismisses can sit over content for good. Escape, the same button and Tab all close it here.

Notes

Building it

  • The live region is in the page from the start. The script empties it and writes the note in a moment later, which screen readers announce reliably; a region added together with its text often is not.
  • role=status is polite, so the note waits until the screen reader has finished saying the button's state.
  • The note sits right after its button in the DOM, so anyone reading on through the page meets it in the right place too.
  • Keep the note to plain text of a sentence or two. The script places it above the button, or below when there is no room, and keeps it inside the card.

Sources: Inclusive Components: Tooltips and Toggletips · WAI-ARIA 1.2: the status role

Checked with axe in light and dark themes, at desktop and phone widths, and by keyboard. Not yet tested with every screen reader and browser pair. Report a correction