Describes the action/purpose of an icon button.


Tooltip is a hover and focus-activated flyout.

A tooltip describes the primary action of an interactive control. This content appears inside of an overlay when the control receives hover or focus.

In desktop software tooltips are most commonly used in relation to toolbar buttons (e.g. the trashcan icon in a mail app). Web tooltips are more commonly experienced in relation to links, buttons and form controls.

Working Examples

You can take a look at the tooltip pattern in action on our examples site.


We use the following terminology when discussing this pattern.

  • tooltip: the composite pattern as a whole, containing a host and overlay

  • host: the control that hosts the overlay

  • overlay: the overlay that contains the tip

  • tip: the content inside of the overlay

Best Practices

First of all, the HTML title attribute is not an accessible tooltip. Read the title tooltip anti-pattern for more details.

Secondly, the tooltip must describe the host element only. Do not create a host element (e.g. a button) purely for the sake of displaying an overlay. If that is your wish, consider the Infotip pattern instead.

Tooltip must not be applied to static elements. See the non-interactive hover anti-pattern.

Tooltip must not use the aria-haspopup attribute. Tooltips are not considered 'popups' in this context.

Tooltip should not be more than one sentence. Consider using the Infotip pattern for longer content.

Tooltip should follow the principal of progressive disclosure - revealing the right information, at the right time.

If the tooltip conveys crucial information, overlay content should be visible in a no-JavaScript state (i.e. use progressive enhancement).

Interaction Design

This section provides the pattern interaction design for keyboard, screen reader, mouse & touch.


Host must be keyboard focusable.

Overlay must appear after short delay when host receives focus.

Keyboard focus order must move from host to first focusable control in overlay.

Overlay must disappear when focus leaves flyout.

Focus should not move to overlay element itself, only its focusable children.


Assistive technology that supports tooltip role will announce the overlay content after a short delay. This delay is configurable in most screen readers.

Reading order must flow directly from host into overlay.


Overlay must appear after short delay whenever host receives mouseover.

Overlay must disappear when neither the host or overlay have mouseover.


Many touch devices do not support hover interactions!

You should consider using the click-activated Bubble Help pattern instead.

Developer Guide 1 - Progressive Enhancement

Our first guide follows the Progressive Enhancement strategy. Building in a layered fashion allows everyone to access the basic content and functionality of a web page.

The three layers are:

  1. Content (HTML)

  2. Presentation (CSS)

  3. Behaviour (JS)

The tooltip content is fully visible and accessible without CSS and JavaScript.

Content (HTML)

The goal of our content layer is to add helpful, advisory content (our "tip") to an existing page control.

Identify Element

First we identify the host that requires a tooltip We will use the "Add to Cart" submit button in a form.

  <input type="submit" value="Add to Cart" />

This button is a form submit button and does not require client-side script to operate. The request can be processed by the server.

Add Content

We place our content element directly after the submit button.

  <input type="submit" value="Add to Cart" />
  <span>Your cart contains <a href="">6 items</a></span>

The content sits in a new span element which will later act as the overlay.

Notice that our tooltip content contains a nested hyperlink. We must also ensure that any content inside of the overlay is accessible too.

The Tooltip Role

ARIA defines a tooltip role. We add this role not to the host, but the element hosting the content.

  <input type="submit" value="Add to Cart" aria-describedby="tooltip1" />
  <span id="tooltip1" role="tooltip">Your cart contains <a href="">6 items</a></span>

The span element now has role=tooltip and a unique id. The unique ID is essential so that the button can reference the tooltip in its aria-describedby attribute.

Widget Root

We wrap our host and overlay elements together in a new parent element to form the root element for our tooltip widget:

  <span class="tooltip">
    <input type="submit" value="Add to Cart" aria-describedby="tooltip1" />
    <span id="tooltip1" role="tooltip">(Your cart contains <a href="">6 items</a>)</span>

We give our widget a class of 'tooltip'; our hook for CSS and JavaScript.


Our markup is now complete. The button, its hint content and the link inside of the hint content are all functional and accessible.

Presentation (CSS)

We could use pure CSS and display the hint using the :hover and :focus pseudo selectors. However, we would soon run into accessibility issues. When keyboard users tab away from the button, the tooltip overlay would disappear. This behaviour prevents focus on any links inside of the tooltip overlay. We need to use JavaScript to prevent this behaviour.


To be able to position the overlay with JavaScript, we set either absolute or fixed positioning:

.tooltip--js [role=tooltip] {
    display: none;
    position: absolute;
    white-space: nowrap;
    z-index: 1;

Notice we are using the tooltip--js selector. JavaScript can add this modifier class when the widget has fully initialised. Our tooltip isn't hidden until that time. This ensures that the tooltip content is readable and accessible without JavaScript.


Our presentation is now complete. At this point, the content remains fully visible and accessible.

Behaviour (JS)

The goal of our JavaScript layer is control the visibility of the tooltip content.


The overlay must be visible only while mouse remains hovered over the host element, or while keyboard focus remains on the element.

Fortunately, the makeup-expander module handles this behaviour for us in just a few lines of code.

this.expander = new Expander(widgetEl, {
    autoCollapse: true,
    contentSelector: '.tooltip__content',
    hostSelector: '.tooltip__host',
    expandOnFocus: true,
    expandOnHover: true

This pattern lays the foundation for creating an accessible tooltip.

Developer Guide 2

Our second developer guide focuses on a non-progressive enhancement scenario.

This is actually a common scenario for most button-based tooltips. Often the tooltip content relates to a behaviour or action performed by a button. For example, toolbar buttons on an inline HTML editor. Without JavaScript, the button is non-operable and so the tooltip is redundant.

Developer guide coming soon, in the meantime please read the progressive enhancement guide.


What is the difference between Infotip Button and Tooltip?

A tooltip provides a tip about the primary action of an interactive element (typically a button). For example, the trashcan icon button in your mail application. The tooltip can be thought of as the secondary action of the button. It is always triggered by focus and hover.

An infotip button provides a tip about a nearby static element or content. It is always triggered by click.

This is different to the way Bootstrap Tooltip works. Why?

The fundamental difference is that the Bootstrap Tooltip get it's content from the title attribute, whereas the pattern presented here gets it's content from an element's innerHTML. This allows us to more easily place HTML such as hyperlinks inside of our tooltips and, unlike Bootstrap, the tooltip content will be fully accessible without JavaScript.

Why do we need JavaScript at all? Can't we do a tooltip with just CSS?

A pure CSS solution only gets us so far, it could not cover the following situations:

  • Delay before showing overlay

  • Keyboard focus management

  • Overlay re-positioning logic when scrolling or near edge of screen


  • makeup-expander: creates the basic accessibility for an element that expands and collapses another element (e.g. a fly-out or fly-in).

Last updated