Skip to main content

Cursor

The Cursor component creates an interactive custom cursor that follows the mouse movement within a defined area. It hides the default cursor and displays custom content (text, icons, or React components) that tracks mouse position in real-time.

Installation

npm install @craftdotui/components

Import

import Cursor from "@craftdotui/components";

Usage

import Cursor from "@craftdotui/components";

export default function Example() {
  return (
    <Cursor cursor="View">
      <div className="w-full h-64 bg-gray-100 rounded-lg">
        <p className="p-8">Hover over this area</p>
      </div>
    </Cursor>
  );
}

Props

children
React.ReactNode
required
The content area where the custom cursor will be active.
cursor
string | React.ReactNode
required
The custom cursor content. Can be a string for simple text or a React component for complex cursors.
className
string
Additional CSS classes to apply to the container element.

Interaction Details

Cursor Positioning

The cursor uses precise calculations to track mouse position:
const rect = containerRef.current?.getBoundingClientRect();
setCursorPosition({
  x: e.clientX - rect.left,
  y: e.clientY - rect.top,
});

Transform Origin

The cursor is centered on the mouse position using:
transform: translate(-50%, -50%);
transform-origin: left center;
The default cursor is automatically hidden when hovering over the component area using cursor: none.

Examples

Call-to-Action Card

import Cursor from "@craftdotui/components";
import { ArrowRight } from "lucide-react";

export default function CTACard() {
  return (
    <Cursor 
      cursor={
        <div className="bg-black text-white px-4 py-2 rounded-full flex items-center gap-2">
          <span>Click me</span>
          <ArrowRight className="w-4 h-4" />
        </div>
      }
    >
      <div className="w-full h-96 bg-gradient-to-br from-indigo-500 to-purple-600 rounded-xl flex items-center justify-center">
        <h2 className="text-white text-4xl font-bold">Explore More</h2>
      </div>
    </Cursor>
  );
}

Product Showcase

import Cursor from "@craftdotui/components";
import { ZoomIn } from "lucide-react";

export default function ProductShowcase() {
  return (
    <div className="grid grid-cols-3 gap-4">
      {products.map((product) => (
        <Cursor 
          key={product.id}
          cursor={
            <div className="bg-white p-3 rounded-full shadow-xl">
              <ZoomIn className="w-5 h-5" />
            </div>
          }
        >
          <img 
            src={product.image} 
            alt={product.name}
            className="w-full h-64 object-cover rounded-lg"
          />
        </Cursor>
      ))}
    </div>
  );
}

Interactive Text

import Cursor from "@craftdotui/components";

export default function InteractiveText() {
  return (
    <Cursor 
      cursor={
        <span className="text-2xl font-bold text-pink-500">👆</span>
      }
      className="p-12"
    >
      <p className="text-6xl font-bold leading-relaxed">
        Hover over this text to see the magic
      </p>
    </Cursor>
  );
}
Use whitespace-nowrap class on the cursor content to prevent text wrapping for multi-word labels.

Use Cases

  • Video players: Show play/pause controls on hover
  • Image galleries: Display zoom or drag indicators
  • Product cards: Indicate clickable areas
  • Interactive presentations: Guide user attention
  • Creative portfolios: Add unique brand interactions

Accessibility

Custom cursors can impact accessibility. Ensure:
  • The cursor content is visible against all backgrounds
  • Touch devices fallback gracefully (no cursor events)
  • Keyboard navigation alternatives are provided

Build docs developers (and LLMs) love