Accessibility pattern · Overlays

Tooltip

A tooltip is text tied to a button: it names an icon button through aria-labelledby, or adds a hint to a labelled one through aria-describedby. It appears on keyboard focus as well as hover, stays while the pointer moves onto it, and Escape hides it without moving focus.

WCAG criteria
5
Keyboard rules
2
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.

To Rohan Mehta

Site visit on Friday

Draft

Friday at 11 works for me. I will bring the revised floor plan and the tile samples for the kitchen.

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
Tab or ShiftTabMoves to a button; its tooltip appears after a short pause, or at once if a neighbour's was just showing, and hides when focus moves on.
EscapeHides the open tooltip without moving focus; it stays hidden until focus or the pointer leaves and comes back.

Screen readers

What it announces

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

WhenExpected announcement
Focus reaches the Send later buttonSend later, button. Pick a time. It goes out even if you close this tab.
Focus reaches the paperclip buttonAttach a file, button
The tooltip appearsNothing extra: its words are already the button's name or description
Escape hides itNothing; focus stays on the button

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-tooltip" data-ap-tooltip>
  <div class="ap-tooltip__top">
    <span class="ap-tooltip__avatar" aria-hidden="true" translate="no">RM</span>
    <div class="ap-tooltip__who">
      <h3 class="ap-tooltip__to">To Rohan Mehta</h3>
      <p class="ap-tooltip__subject">Site visit on Friday</p>
    </div>
    <span class="ap-tooltip__pill">Draft</span>
  </div>
  <p class="ap-tooltip__msg">Friday at 11 works for me. I will bring the revised floor plan and the tile samples for the kitchen.</p>

  <div class="ap-tooltip__bar">
    <div class="ap-tooltip__tools">
      <button type="button" class="ap-tooltip__icon" id="tooltip-attach-btn" aria-labelledby="tooltip-attach">
        <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="m21.4 11.1-9.2 9.2a6 6 0 0 1-8.5-8.5l8.6-8.6a4 4 0 0 1 5.7 5.7l-8.6 8.6a2 2 0 0 1-2.8-2.8l8.5-8.5"/></svg>
      </button>
      <div class="ap-tooltip__tip" role="tooltip" id="tooltip-attach" popover="manual">Attach a file</div>

      <button type="button" class="ap-tooltip__icon" id="tooltip-photo-btn" aria-labelledby="tooltip-photo">
        <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="9" cy="9" r="2"/><path d="m21 15-3.1-3.1a2 2 0 0 0-2.8 0L6 21"/></svg>
      </button>
      <div class="ap-tooltip__tip" role="tooltip" id="tooltip-photo" popover="manual">Insert a photo</div>
    </div>

    <button type="button" class="ap-btn ap-btn--primary" id="tooltip-later-btn" aria-describedby="tooltip-later">
      <svg class="ap-btn__icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>
      Send later
    </button>
    <div class="ap-tooltip__tip" role="tooltip" id="tooltip-later" popover="manual">Pick a time. It goes out even if you close this tab.</div>
  </div>
</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

    The icon buttons take their names from their tooltips, so a picture of a paperclip is announced as Attach a file.

  • 1.4.13 Content on Hover or Focus Level AA

    Escape hides the tooltip without moving the pointer or focus, the pointer can move onto it, and it stays until hover and focus have both left.

  • 2.1.1 Keyboard Level A

    Every tooltip appears on keyboard focus, not only on hover, so keyboard users see the same words.

  • 2.4.11 Focus Not Obscured (Minimum) Level AA

    The tooltip sits beside its button, never over it, and flips below when there is no room above, so the focused button stays in view.

  • 4.1.2 Name, Role, Value Level A

    role=tooltip, with the button pointing at it through aria-labelledby or aria-describedby, puts the words in the button's name or description.

Usage

When to use it

Use it

  • The name of an icon-only button, for people who can see the icon but cannot guess what it does.
  • A short hint that adds to a visible label, like what Send later actually does.

Use something else

  • Anything people need to finish a task: put it on the page, where everyone sees it.
  • Links, buttons or fields: a tooltip cannot take focus, so use a popover or a toggletip instead.
  • Touch-first screens, where there is no hover: use visible labels or a toggletip.

Common failures

How it usually goes wrong

  • Hover only

    A tooltip that appears on mouseover alone is never seen by keyboard users. Here it also appears when the button receives keyboard focus.

  • It vanishes when you reach for it

    If moving the pointer from the button to the tooltip closes it, people who zoom in cannot read it. A short grace period and an invisible bridge over the gap keep it open.

  • No way to put it away

    A tooltip that covers other content must be dismissible without moving the pointer or focus. Escape hides it, and it stays hidden until you leave and come back.

  • The title attribute as the tooltip

    title text does not appear on keyboard focus or touch, shows after a long delay and cannot be styled. A real element with role=tooltip does all three.

  • A tooltip on something that cannot take focus

    A hint on a plain icon or a span is out of reach for keyboard and screen reader users. Put it on a button, a link or a field.

  • Links or buttons inside the tooltip

    Focus cannot move into a tooltip, so controls inside it are unreachable. If the content needs a link, it is a popover or a toggletip.

Notes

Building it

  • Use aria-labelledby when the tooltip is the only label, as on an icon button, and aria-describedby when it adds to a visible label. Never put the same words in both.
  • popover=manual puts the tooltip in the top layer, so no ancestor with overflow: hidden can clip it, while it stays next to its button in the DOM and the accessibility tree.
  • The short delay stops tooltips flashing as the pointer crosses a toolbar; once one is showing, its neighbours appear at once.
  • Touch screens have no hover, and a tap does not set focus-visible, so nothing appears there. Never put information only in a tooltip.
  • The script places the tooltip with getBoundingClientRect and moves it with the page as it scrolls; CSS anchor positioning can do the same job where it is supported.

Sources: WAI-ARIA Authoring Practices: Tooltip · Understanding WCAG 2.2: Content on Hover or Focus

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