BlobCursor
react-bits/BlobCursor-TS-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-TS-CSS.jsonSource
1'use client';23import React, { useRef, useEffect, useCallback } from 'react';4import gsap from 'gsap';5import './BlobCursor.css';67export interface BlobCursorProps {8 blobType?: 'circle' | 'square';9 fillColor?: string;10 trailCount?: number;11 sizes?: number[];12 innerSizes?: number[];13 innerColor?: string;14 opacities?: number[];15 shadowColor?: string;16 shadowBlur?: number;17 shadowOffsetX?: number;18 shadowOffsetY?: number;19 filterId?: string;20 filterStdDeviation?: number;21 filterColorMatrixValues?: string;22 useFilter?: boolean;23 fastDuration?: number;24 slowDuration?: number;25 fastEase?: string;26 slowEase?: string;27 zIndex?: number;28}2930export default function BlobCursor({31 blobType = 'circle',32 fillColor = '#5227FF',33 trailCount = 3,34 sizes = [60, 125, 75],35 innerSizes = [20, 35, 25],36 innerColor = 'rgba(255,255,255,0.8)',37 opacities = [0.6, 0.6, 0.6],38 shadowColor = 'rgba(0,0,0,0.75)',39 shadowBlur = 5,40 shadowOffsetX = 10,41 shadowOffsetY = 10,42 filterId = 'blob',43 filterStdDeviation = 30,44 filterColorMatrixValues = '1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 35 -10',45 useFilter = true,46 fastDuration = 0.1,47 slowDuration = 0.5,48 fastEase = 'power3.out',49 slowEase = 'power1.out',50 zIndex = 10051}: BlobCursorProps) {52 const containerRef = useRef<HTMLDivElement>(null);53 const blobsRef = useRef<(HTMLDivElement | null)[]>([]);5455 const updateOffset = useCallback(() => {56 if (!containerRef.current) return { left: 0, top: 0 };57 const rect = containerRef.current.getBoundingClientRect();58 return { left: rect.left, top: rect.top };59 }, []);6061 const handleMove = useCallback(62 (e: React.MouseEvent<HTMLDivElement> | React.TouchEvent<HTMLDivElement>) => {63 const { left, top } = updateOffset();64 const x = 'clientX' in e ? e.clientX : e.touches[0].clientX;65 const y = 'clientY' in e ? e.clientY : e.touches[0].clientY;6667 blobsRef.current.forEach((el, i) => {68 if (!el) return;69 const isLead = i === 0;70 gsap.to(el, {71 x: x - left,72 y: y - top,73 duration: isLead ? fastDuration : slowDuration,74 ease: isLead ? fastEase : slowEase75 });76 });77 },78 [updateOffset, fastDuration, slowDuration, fastEase, slowEase]79 );8081 useEffect(() => {82 const onResize = () => updateOffset();83 window.addEventListener('resize', onResize);84 return () => window.removeEventListener('resize', onResize);85 }, [updateOffset]);8687 return (88 <div89// … 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 |
