BlobCursor
react-bits/BlobCursor-JS-CSSFreeComponent
Organic blob cursor that smoothly follows the pointer with inertia and elastic morphing.
Live preview
live · rendered by the registry
Rendered by @react-bits on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://www.reactbits.dev/r/BlobCursor-JS-CSS.jsonSource
1'use client';23import { useRef, useEffect, useCallback } from 'react';4import gsap from 'gsap';5import './BlobCursor.css';67export default function BlobCursor({8 blobType = 'circle',9 fillColor = '#5227FF',10 trailCount = 3,11 sizes = [60, 125, 75],12 innerSizes = [20, 35, 25],13 innerColor = 'rgba(255,255,255,0.8)',14 opacities = [0.6, 0.6, 0.6],15 shadowColor = 'rgba(0,0,0,0.75)',16 shadowBlur = 5,17 shadowOffsetX = 10,18 shadowOffsetY = 10,19 filterId = 'blob',20 filterStdDeviation = 30,21 filterColorMatrixValues = '1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 35 -10',22 useFilter = true,23 fastDuration = 0.1,24 slowDuration = 0.5,25 fastEase = 'power3.out',26 slowEase = 'power1.out',27 zIndex = 10028}) {29 const containerRef = useRef(null);30 const blobsRef = useRef([]);3132 const updateOffset = useCallback(() => {33 if (!containerRef.current) return { left: 0, top: 0 };34 const rect = containerRef.current.getBoundingClientRect();35 return { left: rect.left, top: rect.top };36 }, []);3738 const handleMove = useCallback(39 e => {40 const { left, top } = updateOffset();41 const x = 'clientX' in e ? e.clientX : e.touches[0].clientX;42 const y = 'clientY' in e ? e.clientY : e.touches[0].clientY;4344 blobsRef.current.forEach((el, i) => {45 if (!el) return;46 const isLead = i === 0;47 gsap.to(el, {48 x: x - left,49 y: y - top,50 duration: isLead ? fastDuration : slowDuration,51 ease: isLead ? fastEase : slowEase52 });53 });54 },55 [updateOffset, fastDuration, slowDuration, fastEase, slowEase]56 );5758 useEffect(() => {59 const onResize = () => updateOffset();60 window.addEventListener('resize', onResize);61 return () => window.removeEventListener('resize', onResize);62 }, [updateOffset]);6364 return (65 <div66 ref={containerRef}67 className="blob-container"68 style={{ zIndex }}69 onMouseMove={handleMove}70 onTouchMove={handleMove}71 >72 {useFilter && (73 <svg style={{ position: 'absolute', width: 0, height: 0 }}>74 <filter id={filterId}>75 <feGaussianBlur in="SourceGraphic" result="blur" stdDeviation={filterStdDeviation} />76 <feColorMatrix in="blur" values={filterColorMatrixValues} />77 </filter>78 </svg>79 )}8081 <div className="blob-main" style={{ filter: useFilter ? `url(#${filterId})` : undefined }}>82 {Array.from({ length: trailCount }).map((_, i) => (83 <div84// … truncated
What it pulls in
npm packages
Files it writes
More from @react-bits
All 556 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| AnimatedContentAnimatedContent-JS-CSS | @react-bits | Components | Free | 1 dep | |
| AnimatedContentAnimatedContent-JS-TW | @react-bits | Components | Free | 1 dep | |
| AnimatedContentAnimatedContent-TS-CSS | @react-bits | Components | Free | 1 dep | |
| AnimatedContentAnimatedContent-TS-TW | @react-bits | Components | Free | 1 dep | |
| AnimatedListAnimatedList-JS-CSS | @react-bits | Components | Free | 1 dep · 2 files | |
| AnimatedListAnimatedList-JS-TW | @react-bits | Components | Free | 1 dep | |
| AnimatedListAnimatedList-TS-CSS | @react-bits | Components | Free | 1 dep · 2 files | |
| AnimatedListAnimatedList-TS-TW | @react-bits | Components | Free | 1 dep |
