ui-014

Animated Tooltip

£10 or the whole Vault, £99

An animated tooltip that travels between targets: one bubble tweens its position, size and arrow instead of blinking out and back in.

intermediate
5 more details
micro-interactionmorphinghover-effectshared-elementpointer-tracking

This element reads better at your own screen size than in the frame below:

Updated

About this component

A tooltip layer built from a single bubble. The first hover fades one in after a short delay, and every hover after that moves the same element: its x, y, width and height all tween together while the arrow slides along the edge and keeps pointing at the target. Moving along a row of targets reads as one object travelling, which is what separates it from a stack of tooltips appearing and disappearing. A target carrying a breakdown rather than a sentence morphs the same bubble into a small popover of label and value rows.

Read the full effect overview

A single self-contained component: one HTML file, one stylesheet, one script, vanilla JavaScript and core GSAP, no framework and no plugins. Light and dark themes are one design at two sets of token values, switched with one data-variant attribute.

Animated Tooltip - UI component preview

What's included

9 items
  • One bubble for every target, morphing position and size between them
  • A plain tooltip or a label-and-value breakdown from the same bubble, via data-tip-rows
  • Arrow tracks the target centre and clamps to the bubble's edge on long labels
  • Flips to the opposite side when the preferred side runs out of viewport
  • A delay before the first show, then instant morphing while the bubble is up
  • An offscreen twin measures the next box, so the size tween never guesses
  • Keyboard focus shows the tooltip exactly as hover does, Escape dismisses it
  • Native title attributes are the no-JS fallback, stripped once the script runs
  • Light and dark themes, every colour a custom property

Perfect for

4 use cases
  • Dense settings and billing panels where every field needs a note
  • Toolbars and icon rails with no room for labels
  • Documentation and pricing pages explaining inline terms
  • Dashboards where several tooltips sit close enough to be read in sequence

How it works

3 sections

Measure, then morph

An offscreen twin of the bubble carries the same padding, font and max-width. Filling it with the next target's content, a sentence or a set of rows, gives the exact box the bubble is about to occupy, so one tween moves and resizes it in a single motion instead of snapping the size and hoping the text fits.

Arrow and flipping

The arrow is a sibling of the bubble rather than a child, because the bubble clips its own overflow while its box tweens. Its position is solved in viewport coordinates from the target's centre and clamped to stay on the bubble's edge, and the same solve step flips the placement to the opposite side whenever the preferred side would cross the viewport margin.

Delay and warmth

The first hover waits out a short delay so a cursor crossing the page does not fire tooltips. Once one is up, and for a moment after it hides, the layer stays warm and every further hover paints immediately, which is what makes a run of targets read as one bubble travelling.

Difficulty Intermediate
Includes HTML + JS + CSS source, documentation, AI setup prompt, lifetime updates

Lighthouse, as measured

Google Lighthouse on this UI element's demo, from the latest scan. A measurement of the demo as shipped, not a promise for your page.

Accessibility
100
Best practices
100

No performance score, on purpose. That figure depends on how you deploy: your server's compression and caching, your CDN, the connection and the device doing the test, none of which the code controls. The same page can score very differently on two consecutive runs, so measure it where it will live.

Paid UI element

Purchase to unlock the code.

Buying Animated Tooltip opens the HTML, CSS and JavaScript source, the full documentation, an AI setup prompt for your editor, and every update we ship to it. Standard license: unlimited personal and commercial projects. Every paid product is tested for desktop and mobile layouts, reduced-motion handling, animation cleanup and keyboard controls wherever there is something to operate.

£10 Standard license, unlimited projects

Browse UI elements

Or the whole library: the Vault, £99, one payment.

Documentation

What's Included

  • index.html: the demo page and the markup to copy

  • assets/style.css: component styles and the two theme blocks, plain CSS custom properties

  • assets/script.js: readable, commented source with an onReady guard

  • One bubble for every target, morphing position and size between them

  • A plain tooltip or a label-and-value breakdown from the same bubble

  • Arrow tracks the target centre and clamps to the bubble's edge

  • Flips to the opposite side near a viewport edge

  • A delay before the first show, then instant morphing while the bubble is up

  • Focus shows the tooltip exactly as hover does, Escape dismisses it

  • Native title attributes are the no-JS fallback

Quick Start

1. Add to your HTML <head>:

Code snippet omitted: it ships with the download.

2. Add to your <body>:

Copy the bubble, the arrow and the measuring twin from the bottom of index.html:

Code snippet omitted: it ships with the download.

Then give anything that should have a tooltip the class tip-target and a title:

Code snippet omitted: it ships with the download.

For a breakdown instead of a sentence, add data-tip-rows (the title stays as the no-JS fallback):

Code snippet omitted: it ships with the download.

3. Add before the closing </body> tag:

Code snippet omitted: it ships with the download.

Themes

The component ships in two themes, light (the default) and dark: one design at two sets of token values. Set the attribute on <body> in the demo, or on the component's root in your own page:

Code snippet omitted: it ships with the download.

Nothing else changes: same markup, same script, and no theme name is ever read in JavaScript. Both blocks live at the top of assets/style.css and define every colour, radius and shadow the component uses:

Token What it colours
--tip-bg, --tip-fg the bubble and its text (the arrow reads --tip-bg, so the two can never drift apart)
--tip-muted the label column of a data-tip-rows breakdown
--tip-border, --tip-radius, --tip-shadow the bubble's edge, corner and elevation
--tip-font-size, --tip-weight the bubble's type
--accent, --accent-ink the focus ring, the selection colour and the primary trigger
--ground, --ground-2, --raised, --hover surfaces
--ink, --ink-2, --ink-3, --line, --line-strong text and hairlines

To re-value it for your own brand, change those properties in the two body[data-variant="..."] blocks; nothing else in the stylesheet holds a colour.

Demo furniture. The 44px toolbar strip at the top of index.html (the prompt, the placement control and the Light/Dark toggle), the .stage wrapper and the ?variant= script are demo-only. They live in index.html, never in assets/, and are not part of what you bought. The trigger row itself (.tip-row, .tip-icon, .tip-button) is ordinary product markup: keep it, restyle it, or drop your own controls in.

How It Works

Measure, then morph. An offscreen twin of the bubble carries the same padding, font and max-width. Filling it with the next target's content gives the exact box the bubble is about to occupy, so a single gsap.to tweens x, y, width and height together on a power3.out ease instead of snapping the size and hoping the text fits.

Arrow and flipping. The arrow is a sibling of the bubble rather than a child, because the bubble clips its own overflow while its box tweens and a child arrow would be clipped with it. Its position is solved in viewport coordinates from the target's centre and clamped to stay on the bubble's edge; the same solve step flips the placement to the opposite side whenever the preferred side would cross the viewport margin.

Delay and warmth. The first hover waits out a short delay so a cursor crossing the page does not fire tooltips. Once one is up, and for a moment after it hides, the layer stays warm and every further hover paints immediately.

Options

Attribute Values Default Description
title any text none The tooltip text. Read once on load, then removed so the browser's own tooltip does not appear on top
data-tip-rows Label | Value pairs, separated by ; none A breakdown instead of a sentence. Each pair becomes one row, label left and value right. Wins over title, which stays as the no-JS fallback
data-tip-place top, right top Preferred side. top flips to bottom near the top edge, right flips to left near the right edge

Customisation

What Where
Delay before the first show FIRST_DELAY in assets/script.js (default 340ms)
Warm window after hiding WARM (default 450ms)
Distance from the target GAP (default 10px)
Viewport margin used for flipping EDGE (default 10px)
Arrow size ARROW in the script and the border-width on .tip-arrow
Morph speed the duration: dur(0.44) and power3.out ease in paint
Breakdown layout .tip-rows, .tip-rowline in assets/style.css
Colours, radii, shadows the body[data-variant] blocks in assets/style.css

Accessibility

  • Targets are real <button> elements, so they are tabbable and the tooltip shows on focus as well as hover.
  • The active target gets aria-describedby="tipBubble", and the bubble is role="tooltip". The attribute is removed from every other target, and from all of them when the bubble hides.
  • Escape dismisses the bubble without moving focus.
  • Without JavaScript the title attributes are untouched, so every target still explains itself through the browser's own tooltip.
  • prefers-reduced-motion: reduce sets every duration to zero and skips the show delay, so the tooltip appears and moves instantly rather than not at all.

Requirements

  • GSAP 3.12+ (core only)
  • No build step, no framework

Worked examples, the events and programmatic API, and the class reference ship with the download, alongside the full source.