Tooltip

Hover- and focus-triggered tooltip anchored to its trigger.

organismsSource
import { Tooltip, TooltipContent, TooltipTrigger } from '@elirobinson/react/components/organisms/Tooltip';

Styles: @elirobinson/react/styles/organisms/Tooltip.css — already included when you import @elirobinson/react/styles.css.

Show code
import { Button } from '@elirobinson/react/components/atoms/Button';
import {
  Tooltip,
  TooltipContent,
  TooltipTrigger,
} from '@elirobinson/react/components/organisms/Tooltip';

export default function Basic() {
  return (
    <Tooltip>
      <TooltipTrigger>
        <Button variant="secondary">Export as PDF</Button>
      </TooltipTrigger>
      <TooltipContent>Includes your session notes and the printable drill cards.</TooltipContent>
    </Tooltip>
  );
}

When to use it

Use Tooltip for a short, supplementary label — what an icon button does, an abbreviation spelled out, a truncated value's full text. It's not for anything the reader needs to read reliably: it only shows on hover or keyboard focus, so it never reaches a touch-only visitor and it's gone the moment focus moves on.

If the content matters enough that someone should be able to read it without hovering, put it in the page instead. If it needs to stay open while the reader interacts with it — a form, a list of actions — use Popover.

Labeling an icon button

A tooltip is a bonus for sighted mouse and keyboard users — it doesn't replace the accessible name an icon-only Button still needs on its own aria-label.

Show code
import { Button } from '@elirobinson/react/components/atoms/Button';
import {
  Tooltip,
  TooltipContent,
  TooltipTrigger,
} from '@elirobinson/react/components/organisms/Tooltip';

export default function IconButton() {
  return (
    <Tooltip>
      <TooltipTrigger>
        <Button variant="ghost" aria-label="Download guide">
          <svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true">
            <path
              d="M8 1v9m0 0 3-3m-3 3-3-3M2 12v2a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1v-2"
              stroke="currentColor"
              strokeWidth="1.5"
              strokeLinecap="round"
              strokeLinejoin="round"
            />
          </svg>
        </Button>
      </TooltipTrigger>
      <TooltipContent>Download guide</TooltipContent>
    </Tooltip>
  );
}

Props

PropTypeDefaultDescription
delayDurationnumber

TooltipContent

No props of its own beyond the inherited HTML attributes.

Also accepts all HTMLAttributes<HTMLDivElement> props.

TooltipTrigger

No props of its own beyond the inherited HTML attributes.

Also accepts all HTMLAttributes<HTMLSpanElement> props.

Accessibility

  • TooltipTrigger wraps its child in a <span> carrying aria-describedby pointed at the tooltip content's id — wrap a real interactive element (a button, a link) inside it so there's something to hover or focus in the first place.
  • Keyboard: opens on native focus, closes on blur. There's no separate keyboard path to keep in sync with hover — focusing the wrapped element opens the tooltip the same way hovering it does.
  • No Escape handling — pressing it does not close the tooltip. Moving focus or the pointer away is the only way to dismiss it.
  • TooltipContent renders through a portal to document.body and only mounts while open — it isn't hidden with CSS, so there's nothing sitting in the DOM to tab into while closed.
  • Position is fixed: centered under the trigger, a few pixels below it. There's no side/alignment prop to place it anywhere else.

Do

  • Wrap a genuinely focusable element in TooltipTrigger — a button, a link, an input — so keyboard users can reach it at all.
  • Give icon-only buttons their own aria-label even inside a Tooltip — the tooltip supplements it, it does not replace it.
  • Keep TooltipContent to a short phrase — it is a label, not a place for instructions someone needs to act on.
  • Use it only for information that is genuinely optional — the layout should still make sense if the tooltip never appears.

Don't

  • Put interactive content — a link, a button — inside TooltipContent; it disappears the moment focus or the pointer leaves the trigger, before a reader could reach it.
  • Rely on a tooltip to convey something required for the task — touch-only visitors will never see it.
  • Expect Escape to close it — nothing listens for that key here; move focus or the pointer instead.
  • Wrap plain, non-focusable text in TooltipTrigger and expect Tab to reach it.