Skip to content
Gloss v2.0.0
Source
Components

Tooltip

Dark mono tooltip on hover, positioned above the child. Pure CSS — shown on hover and keyboard focus, no JavaScript required.

Basic

role="tooltip" is the correct ARIA role for the bubble itself, so it doubles as the styling hook — no class on the bubble. The wrapping <span> has no attribute of its own, but it does not need one: :has() selects “a span that contains a [role=tooltip] bubble” precisely, so the wrapper stays bare too. Pair the trigger’s aria-describedby with the bubble’s id so the tooltip is announced, not just shown.

Hover or tab to the button below.

Tooltip
Delete
Markup
<span>
  <button class="icon-button" aria-label="Delete" aria-describedby="tooltip-basic">
    <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 7h16M9 7V4h6v3M6 7l1 13h10l1-13" /></svg>
  </button>
  <span role="tooltip" id="tooltip-basic">Delete</span>
</span>

On any element

A Tooltip wraps whatever it labels — most often an IconButton, since that is the control with no visible text of its own.

On a badge
3d overdue Due Tuesday, was Saturday
Markup
<span>
  <span class="badge" data-tone="danger" tabindex="0" aria-describedby="tooltip-badge">3d overdue</span>
  <span role="tooltip" id="tooltip-badge">Due Tuesday, was Saturday</span>
</span>

API

Element / attributeValuesNotes
spanRequired wrapper around the trigger and the bubble. Bare — matched structurally via :has(), no class.
[role="tooltip"]string contentRequired — the bubble. Give it an id.
aria-describedbythe bubble's idPut it on the trigger element, which needs a real accessible name of its own — a tooltip is not one.