A floating label that follows the cursor and elastic-pops into view over interactive targets, powered by GSAP.
Made by AxylCursorBubble follows the pointer with gsap.quickTo (a lightweight per-frame tween, cheaper than re-running a full tween every mousemove), offset from the cursor so it reads like a little tag trailing behind it. Each CursorBubbleTarget reports its own label to the bubble on hover, which pops in with an elastic ease and collapses back to a dot-sized, rotated resting state on leave — the same feel as Truus.co's footer link cursor.
Installation
File Structure
Usage
Props
| Prop | Type | Default |
|---|---|---|
children? | ReactNode | - |
className? | string | - |
bubbleClassName? | string | - |
CursorBubbleTarget
| Prop | Type | Default |
|---|---|---|
label? | string | "click" |
children? | ReactNode | - |
className? | string | - |
When to Use
Mount one CursorBubble near the root of a page (or layout) and wrap individual links, logos, or buttons in CursorBubbleTarget to give them a contextual hover hint — "say hi", "watch reel", "to home" — instead of relying on the browser's default cursor alone. It reads best on desktop marketing/portfolio pages with a handful of key links, not dense UI with many small targets.
Only one bubble should be mounted per page; multiple CursorBubble providers will each attach their own pointermove listener and fight over the same targets.
Accessibility
The bubble is aria-hidden and pointer-events: none — it never intercepts clicks or enters the tab order, and screen readers ignore it entirely. It only activates on pointer devices: on touch/coarse pointers it renders nothing, and when prefers-reduced-motion: reduce is set it also doesn't render, watched live via usePrefersReducedMotion so toggling the setting mid-session updates immediately.
Credits
Inspired by Truus.co. Reimplemented for GSAP and React.
Built by Axyl. A motion-first component registry for React.
Last updated: 7/9/2026