Navigation✨ Premium

Tooltip Arrow

Tooltip positioned above its trigger, with a CSS triangle arrow and a rise animation — 100% CSS, zero JS.

CSSHoverArrow

You'll get access to the interactive demo with a free account.

This effect is part of Effect.Labs — 811 vanilla effects, some free, some premium. Navigation has 36 effects, including 4 free. Explore the category →

3 usage examples

Editor toolbar — Icon shortcuts with hover labels — Tooltip Arrow example 1

① Editor toolbar — Icon shortcuts with hover labels

WhenThe interface shows a row of unlabeled icons (Bold, Italic, Link, Image…) and hover reveals the action name and keyboard shortcut.
WhyThe centered tooltip with directional arrow visually anchors the tooltip to its icon even at high density. The gentle rise signals the relationship without pulling focus away from the document being edited.
SettingsPadding reduced to 6px 12px, font-size 0.75rem, tighter gap at bottom: calc(100% + 8px), border-radius 6px.
Diagram editor — Arrowed tooltip on a connection node — Tooltip Arrow example 2

② Diagram editor — Arrowed tooltip on a connection node

WhenA dense canvas displays nodes linked by edges; hovering an anchor port reveals the port name and expected data type.
WhyThe CSS arrow precisely targets the hovered port in a visually compact layout where multiple nodes are close together — a plain centered fade would leave the user unsure which port is described. The gentle rise confirms the interaction without disrupting graph reading.
SettingsGap reduced to bottom: calc(100% + 8px), padding 6px 10px, font-size 0.72rem, border-radius 6px, border-width 6px for a discreet arrow at canvas scale.
Metrics table — Column header definitions — Tooltip Arrow example 3

③ Metrics table — Column header definitions

WhenA dashboard shows technical abbreviations (CAC, LTV, MRR, NPS…) in column headers; hover reveals the full definition and unit.
WhyThe above-positioned tooltip opens upward, away from data rows, without masking values. Opacity fade is less aggressive than an OS tooltip and stays consistent with the design system.
SettingsFont-size 0.8rem, border-radius 6px, subdued shadow rgba(0,0,0,.18) 0 2px 8px, monochrome gradient (#1e40af, #2563eb) for a sober data context.

How it works

The tooltip is a span.tooltip-arrow direct child of the trigger button. It is positioned with position: absolute, anchored via bottom: calc(100% + 12px) (above the parent) and horizontally centered by left: 50%; transform: translateX(-50%). No JS, no DOM measurement at runtime — positioning is entirely declarative.

The downward-pointing arrow is generated by the ::after pseudo-element using the CSS border trick: a zero-size box whose four colored borders form a triangle. border-width: 8px sets the tip size; border-color: #8b5cf6 transparent transparent colors only the top border, leaving the other three invisible — which draws the triangle.

Visibility is driven by the opacity: 0 / visibility: hidden pair at rest and opacity: 1 / visibility: visible via the .tooltip-trigger:hover .tooltip-arrow selector. The visibility property is needed alongside opacity: without it, the invisible span would intercept mouse events from elements below.

The rise animation is produced by transform: translateX(-50%) translateY(-5px) on hover — the tooltip moves up 5 px from its resting position. The transition opacity .3s, visibility .3s, transform .3s orchestrates all three properties in parallel. Note: the code contains no prefers-reduced-motion handling — the animation plays regardless of the user's OS motion preference.

Accessibility

  • prefers-reduced-motion absent: the code has no @media (prefers-reduced-motion: reduce) rule. The rise animation and opacity/transform transitions play even when the user has enabled reduced motion in their OS. Fix: add @media (prefers-reduced-motion: reduce) { .tooltip-arrow { transition: opacity .15s, visibility .15s; transform: translateX(-50%) !important; } }.
  • Tooltip/trigger relationship not declared in ARIA: the span has no role="tooltip" and the button has no aria-describedby pointing to it. Screen readers will not read the tooltip on hover.
  • Tooltip not accessible by keyboard focus: the :hover selector does not activate on focus. Add .tooltip-trigger:focus-visible .tooltip-arrow { opacity: 1; visibility: visible; transform: translateX(-50%) translateY(-5px); }.
  • Text contrast: white #fff on indigo gradient #6366f1 → ratio ≈ 5.5:1, WCAG AA met.
  • The trigger is a native HTML <button>: keyboard-focusable, activatable with Enter/Space, visible in the accessibility tree without extra markup.

Browser compatibility

Relies on position: absolute, ::after pseudo-element, transform, transition, opacity and visibility — no JS, no modern API required.

Chrome 60+✓ Full
Firefox 60+✓ Full
Safari 12+✓ Full
Edge 79+✓ Full
Mobile iOS✓ No hover — use :focus
Android Chrome✓ No hover — use :focus

Without <code>transition</code> support (IE 9 and earlier), the tooltip appears and disappears instantly without animation — still functional. On mobile, where the <code>hover</code> event does not exist, the tooltip stays hidden: provide a tap trigger or replace with a JS-driven component.

The code

HTML structure to paste into your page (CSS + JS available with a premium account):

index.html — structure
<div class="demo-preview">
  <div class="component-demo">
    <button class="tooltip-trigger">
      Trigger label
      <span class="tooltip-arrow">Tooltip text</span>
    </button>
  </div>
</div>
🔒 Unlock the full code — from €2.99 the first month

Full HTML + CSS + JS, copy-paste ready — with hundreds of premium effects.

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
.tooltip-arrow background linear-gradient(135deg, #6366f1, #8b5cf6) Tooltip background gradient. Swap in your brand palette — the gradient end color must match the border-color value in ::after.
.tooltip-arrow::after border-color #8b5cf6 transparent transparent Arrow triangle color. Must match the gradient end color of the tooltip for a seamless look.
bottom: calc(100% + 12px) 12px Vertical gap between the trigger top and the tooltip bottom. Increase for more breathing room, decrease for dense UIs.
.tooltip-arrow padding 10px 18px Inner spacing of the tooltip. Reduce to 6px 12px for compact toolbars, increase for long help text.
.tooltip-arrow font-size 0.85rem Text size. 0.75rem for dense toolbars, 0.9rem for help tooltips meant to be read carefully.
.tooltip-arrow border-radius 8px Corner rounding. 4px for a utilitarian style, 12px for a softer design.
.tooltip-arrow::after border-width 8px Arrow tip size in pixels. 5px for a subtle pointer, 12px for a prominent arrow.
transition duration .3s Duration of opacity/visibility/transform transitions. Reduce to .15s for a snappier feel, increase to .5s for a more elegant reveal.

FAQ

The current positioning is purely centered on the parent (left:50%/translateX(-50%)) with no collision detection. For elements near the edge, manually adjust left with a clamped negative offset, or use a contextual positioning library like Floating UI that handles boundary awareness automatically.
The current CSS only triggers the tooltip on mouse hover (:hover). Add this selector for keyboard focus: .tooltip-trigger:focus-visible .tooltip-arrow { opacity: 1; visibility: visible; transform: translateX(-50%) translateY(-5px); }. Also add role="tooltip" to the span and aria-describedby on the button for screen reader support.
Yes, by changing the absolute positioning and arrow direction. For a bottom tooltip: replace bottom: calc(100% + 12px) with top: calc(100% + 12px) and change border-color to transparent transparent #8b5cf6 (upward triangle). For left/right: use right: calc(100% + 12px) or left: calc(100% + 12px) with transform: translateY(-50%) and the matching border-color directions.