Skip to content
Black FridayBlack Friday launch price: Lifetime $149 until 30 Nov. Regular price $299 from 1 Dec.ends in 15d 02:32:11Get Lifetime →
loopkit
proNew153 lines · framer-motion

Cursor Text Label

The pointer tells you what it's about to do. A bounded demo section split into a few labelled tiles. While the pointer stays inside the section, the default cursor is replaced by a spring-smoothed pill that follows it and reads out contextual text for whichever tile is underneath.

Use it for
A features or capabilities grid where each tile has a distinct action, and a small amount of pointer feedback helps a visitor understand what hovering will do before they click.
Themes
Light + dark
License
Commercial use
Live

Cursor

A pointer that explains itself

DragReorder this tile freely.
ViewOpen the full preview.
PlayStart the showcase reel.
LinkFollow this reference out.
tsx
"use client";

import * as React from "react";
import { motion, useMotionValue, useReducedMotion, useSpring } from "framer-motion";
import { cn } from "@/lib/utils";

function useReducedMotionSafe() {
  const prefersReduced = useReducedMotion();
  const [mounted, setMounted] = React.useState(false);
  React.useEffect(() => setMounted(true), []);
  return mounted ? !!prefersReduced : false;
}

/**
 * Bounded demo section with a few labelled zones. While the pointer is inside the
 * section (and only inside it), the real cursor hides and a small spring-smoothed
 * pill follows it, reading contextual text for whichever zone is underneath.
 * Falls back to the plain default cursor on touch devices and under
 * prefers-reduced-motion — no custom tracking runs in either case.
 */

export interface CursorTextLabelZone {

The rest is in Pro.

Full source, the rebuild prompt and registry install unlock with Pro or Lifetime.

Get Pro

How it behaves

  • →onPointerMove/onPointerEnter/onPointerLeave on the section's own root track the pointer only while it is inside that element; nothing is attached to window or document.
  • →Pointer position drives a framer-motion useMotionValue pair smoothed with useSpring, so the pill lags gently behind the real pointer instead of snapping to it.
  • →The pill's text swaps per tile via a data-cursor-zone attribute read through event.target.closest; hovering empty space inside the section shows the neutral idleText instead.
  • →The pill scales and fades in on enter and out on leave via a framer-motion animate transition.
  • →cursor: none is applied to the section element itself, and only once pointer/hover media queries have confirmed a fine pointer is present; it is removed the instant the pointer leaves the section.
  • →On touch devices (pointer: coarse or hover: none) and under prefers-reduced-motion, the whole effect is skipped and the section renders with the plain default cursor.

Accessibility

  • ✓The floating pill is `aria-hidden` and `pointer-events-none`; it never enters the accessibility tree or intercepts clicks.
  • ✓Tiles remain plain content elements with visible text, so the zone labels and descriptions are readable without the pointer effect.
  • ✓No custom cursor or `cursor: none` is ever applied outside the section, and never to `<body>`/`<html>`, so keyboard and touch users keep the native cursor everywhere else.
  • ✓Honours prefers-reduced-motion.