Snippets /

CSS tooltip

A pure-CSS tooltip that reads its text from a data attribute and appears on hover or keyboard focus.

Widely supported
uino-js

Quick implementation

[data-tooltip] {
  position: relative;
}

[data-tooltip]::after {
  content: attr(data-tooltip);
  position: absolute;
  bottom: calc(100% + 0.6rem);
  left: 50%;
  translate: -50% 0.5rem;
  padding: 0.4rem 0.75rem;
  border-radius: 0.35rem;
  background: oklch(0.28 0.02 260);
  color: oklch(0.9 0.01 260);
  font-size: 0.8rem;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease, translate 0.2s ease;
}

[data-tooltip]:hover::after,
[data-tooltip]:focus-visible::after {
  opacity: 1;
  translate: -50% 0;
}

Prompt this to your LLM

Paste this into ChatGPT, Claude, or any code-generating model to scaffold the pattern instantly.

Create a pure CSS tooltip using the ::after pseudo-element
and attr(data-tooltip) for the content. Position the tooltip
above the element, centered horizontally with left: 50% and
translate: -50%. Animate in with opacity and a small upward
slide using the translate property. Show the tooltip on
:hover and :focus-visible. Use oklch() colors for
background and text. Add pointer-events: none to the
pseudo-element so it doesn't block interactions.

Why this matters

Tooltips are one of the most common UI patterns, yet many implementations depend on JavaScript positioning libraries. A pure-CSS approach means zero bundle size, instant rendering, and no layout shift. It works without JavaScript enabled and is trivial to maintain since the tooltip text lives in a data-tooltip attribute right on the element.

The logic

The ::after pseudo-element uses attr(data-tooltip) to pull its text content directly from the HTML attribute. It is positioned absolutely above the trigger element with bottom: calc(100% + 0.6rem) to create a gap. The initial state is opacity: 0 and a slight downward offset via translate. On :hover or :focus-visible, both values transition to their final state, creating a smooth fade-and-slide entrance. The pointer-events: none declaration ensures the tooltip does not intercept mouse events.

Accessibility & performance

CSS-only tooltips have a limitation: screen readers do not announce ::after content reliably across all browsers. For true accessibility, pair this with an aria-label or aria-describedby attribute on the trigger element. Also add role="tooltip" and an id to a real DOM element for screen-reader users if the tooltip conveys essential information. For decorative hints, the CSS-only approach is sufficient. The transition is lightweight and respects prefers-reduced-motion when wrapped in the appropriate media query.