Cursor
motion-primitives/cursorFreeComponent
A custom cursor component with animated effects and interactions.
Install it
npx shadcn@latest add https://raw.githubusercontent.com/ibelick/motion-primitives/HEAD/public/c/cursor.jsonSource
1'use client';2import React, { useEffect, useState, useRef } from 'react';3import {4 motion,5 SpringOptions,6 useMotionValue,7 useSpring,8 AnimatePresence,9 Transition,10 Variant,11} from 'motion/react';12import { cn } from '@/lib/utils';1314export type CursorProps = {15 children: React.ReactNode;16 className?: string;17 springConfig?: SpringOptions;18 attachToParent?: boolean;19 transition?: Transition;20 variants?: {21 initial: Variant;22 animate: Variant;23 exit: Variant;24 };25 onPositionChange?: (x: number, y: number) => void;26};2728export function Cursor({29 children,30 className,31 springConfig,32 attachToParent,33 variants,34 transition,35 onPositionChange,36}: CursorProps) {37 const cursorX = useMotionValue(0);38 const cursorY = useMotionValue(0);39 const cursorRef = useRef<HTMLDivElement>(null);40 const [isVisible, setIsVisible] = useState(!attachToParent);4142 useEffect(() => {43 if (typeof window !== 'undefined') {44 cursorX.set(window.innerWidth / 2);45 cursorY.set(window.innerHeight / 2);46 }47 }, []);4849 useEffect(() => {50 if (!attachToParent) {51 document.body.style.cursor = 'none';52 } else {53 document.body.style.cursor = 'auto';54 }5556 const updatePosition = (e: MouseEvent) => {57 cursorX.set(e.clientX);58 cursorY.set(e.clientY);59 onPositionChange?.(e.clientX, e.clientY);60 };6162 document.addEventListener('mousemove', updatePosition);6364 return () => {65 document.removeEventListener('mousemove', updatePosition);66 };67 }, [cursorX, cursorY, onPositionChange]);6869 const cursorXSpring = useSpring(cursorX, springConfig || { duration: 0 });70 const cursorYSpring = useSpring(cursorY, springConfig || { duration: 0 });7172 useEffect(() => {73 const handleVisibilityChange = (visible: boolean) => {74 setIsVisible(visible);75 };7677 if (attachToParent && cursorRef.current) {78 const parent = cursorRef.current.parentElement;79 if (parent) {80 parent.addEventListener('mouseenter', () => {81 parent.style.cursor = 'none';82 handleVisibilityChange(true);83 });84 parent.addEventListener('mouseleave', () => {85 parent.style.cursor = 'auto';86 handleVisibilityChange(false);87 });88 }89 }9091 return () => {92 if (attachToParent && cursorRef.current) {93 const parent = cursorRef.current.parentElement;94 if (parent) {95 parent.removeEventListener('mouseenter', () => {96// … truncated
What it pulls in
npm packages
Files it writes
More from motion-primitives
All 33 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Accordionaccordion | motion-primitives | Components | Free | 1 dep | |
| Animated Backgroundanimated-background | motion-primitives | Components | Free | 1 dep | |
| Animated Groupanimated-group | motion-primitives | Components | Free | 1 dep | |
| Animated Numberanimated-number | motion-primitives | Components | Free | 1 dep | |
| Border Trailborder-trail | motion-primitives | Components | Free | 1 dep | |
| Carouselcarousel | motion-primitives | Components | Free | 1 dep | |
| Dialogdialog | motion-primitives | Components | Free | 1 dep · 2 files | |
| Disclosuredisclosure | motion-primitives | Components | Free | 1 dep |
