All components Zyqor Components

Component · cursor-follower

Cursor follower

A precise dot and a ring that trails it, grows into a label over work, wraps nav links like a magnet and gets out of the way over text fields. Switches itself off on touch.

Vanilla JS2 KBContext labelsOff on touchReduced motion

On a phone there is no cursor, so this component switches itself off. The tiles keep their own tap and focus states.

Use it

Copy the folder cursor-follower/ (the .js and .css files) into your project. No build step and no framework.

Behaviour

  • Runs only with hover:hover and pointer:fine; on touch it returns null and adds nothing to the page.
  • Over text fields the follower hides and the normal caret shows.
  • The loop stops when the ring has caught up (no idle animation frames).
  • prefers-reduced-motion: no lag, the ring sits exactly on the pointer.
  • Decorative only: aria-hidden, never moves focus.

Credits

  • Spec from Sujon's Drive guide (MA 6.4: dot exact, ring lerp 0.16, context labels, off on touch).
  • Seen on award sites such as A24 by Ravi Klaassens (Awwwards SOTD Oct 26 2026) and Lusion. Written from scratch.
<link rel="stylesheet" href="cursor-follower.css">

<a href="/work/tapehead" data-cursor="View">...</a>
<a href="/studio" data-cursor-stick>Studio</a>
<video data-cursor-hide ...></video>

<script type="module">
  import { cursorFollower } from './cursor-follower.js';
  cursorFollower({ lerp: 0.16, hideNative: true }); // returns null on touch devices
</script>
OptionDefaultWhat it does
lerp0.16Ring lag: 1 = no lag, 0.08 = very floaty. Forced to 1 under reduced motion.
hideNativetrueHide the system cursor (text fields always keep the caret).
data-cursor="Word"Grow into a filled circle that shows the word.
data-cursor-stickRing wraps the element and leans with the pointer.
data-cursor-colorinkRing colour for that element.
data-cursor-hideHide the follower over this element.