abaabil

Tooltip

7th lightest of the twenty-three, by js weight

Shows on hover and on focus, both of which are selectors, so the lower two tiers ship no JavaScript at all.

Read this before using one

A tooltip is the control most often used for the wrong job, so the caveats come before the demo.

  • Never put essential information in one. There is no hover on touch, so it is simply unreachable there. If the user needs it to finish the task, put it on the page.
  • Never put interactive content in one. Moving towards a link inside a tooltip dismisses the tooltip. If you need that, you want a popover.
  • The trigger must be focusable. A tooltip on a plain <span> does not exist for keyboard users. The a11y tier warns when its child cannot receive props.

Example (a11y tier)

Hover either button, or Tab to it. Escape dismisses.

Saves to your account, not just this deviceBelow instead of above

Import

import Tooltip from 'abaabil/tooltip'         // structure only
import Tooltip from 'abaabil/tooltip/styled'  // + CSS, shows on hover/focus
import Tooltip from 'abaabil/tooltip/a11y'    // + aria-describedby, Escape

The showing and hiding is CSS

:hover and :focus-within are the two events that should reveal a tooltip, and both are expressible as selectors. So the normal and styled tiers work with no JavaScript, which is unusual for a component that looks this interactive.

The fade is on the hidden state rather than the shown one, so appearing is instant and can never depend on a transition having run. That is not a preference: an earlier version faded in, and whenever transitions did not advance the bubble sat at zero opacity while every selector said it should be visible. A tooltip that silently never appears is worse than one that never fades.

What the a11y tier adds

aria-describedby from the trigger to the bubble, which is what makes a screen reader read it at all; the CSS tiers show it to sighted users and say nothing to anyone else. And Escape to dismiss, which WCAG 1.4.13 requires for content revealed on hover and which CSS cannot do, because it cannot hear a key. The child is cloned to receive both, so the trigger stays your element rather than a wrapper of ours.

Props

PropTypeDefaultTierDescription
contentReactNodeallThe tooltip text. Keep it short.
placement'top' | 'bottom''top'all
childrenReactElementallThe trigger. Must be focusable.