Docs
Blob Background

Blob Background

A beautiful animated background component with organic, morphing blob shapes.

Organic Design

Attractive fluid shapes for modern interfaces

Installation

Copy and paste the following code into your project.

components/ui/blob-background.tsx

"use client";
 
import React, { useState } from "react";
import { motion, AnimatePresence } from "framer-motion";
import type { MotionStyle, Variants, Transition } from "framer-motion";
 
interface BlobProps {
  color?: string;
  size?: number;
  blur?: number;
  speed?: number;
  opacity?: number;
  zIndex?: number;
  initialPosition?: { x: number; y: number };
  pulseScale?: number;
  rotationSpeed?: number;
  gradientColors?: string[];
}
 
const Blob = ({
  color,
  size = 400,
  blur = 60,
  speed = 20,
  opacity = 0.5,
  zIndex = 0,
  initialPosition = { x: 50, y: 50 },
  pulseScale = 1.1,
  rotationSpeed = 10,
  gradientColors,
}: BlobProps) => {
  const [isHovered, setIsHovered] = useState(false);
 
  const getRandomPoint = () => ({
    x: Math.random() * 100,
    y: Math.random() * 100,
  });
 
  const gradient = gradientColors
    ? `linear-gradient(45deg, ${gradientColors.join(", ")})`
    : color;
 
  const transition: Transition = {
    duration: speed,
    ease: "easeInOut",
    repeat: Infinity,
    repeatType: "reverse",
  };
 
  const rotateTransition: Transition = {
    duration: speed * 2,
    ease: "linear",
    repeat: Infinity,
    repeatType: "loop",
  };
 
  const variants: Variants = {
    initial: {
      x: `${initialPosition.x}%`,
      y: `${initialPosition.y}%`,
      scale: 1,
      rotate: 0,
    },
    animate: {
      x: [
        `${initialPosition.x}%`,
        `${getRandomPoint().x}%`,
        `${getRandomPoint().x}%`,
        `${initialPosition.x}%`,
      ],
      y: [
        `${initialPosition.y}%`,
        `${getRandomPoint().y}%`,
        `${getRandomPoint().y}%`,
        `${initialPosition.y}%`,
      ],
      scale: [1, pulseScale, 1],
      rotate: 360,
      transition: {
        ...transition,
        rotate: rotateTransition,
      },
    },
    hover: {
      scale: 1.1,
      filter: `blur(${blur * 0.8}px)`,
      transition: { duration: 0.3 },
    },
  };
 
  const blobStyle: MotionStyle = {
    position: "absolute" as const,
    width: size,
    height: size,
    filter: `blur(${blur}px)`,
    background: gradient || "transparent",
    borderRadius: "50%",
    opacity,
    zIndex,
    mixBlendMode: "screen" as const,
  };
 
  return (
    <motion.div
      style={blobStyle}
      variants={variants}
      initial="initial"
      animate="animate"
      whileHover="hover"
      onHoverStart={() => setIsHovered(true)}
      onHoverEnd={() => setIsHovered(false)}
    >
      <AnimatePresence>
        {isHovered && (
          <motion.div
            initial={{ opacity: 0, scale: 0.8 }}
            animate={{ opacity: 1, scale: 1 }}
            exit={{ opacity: 0, scale: 0.8 }}
            style={{
              position: "absolute",
              inset: -10,
              background: `radial-gradient(circle, ${
                gradientColors?.[0] || color || "#fff"
              }33 0%, transparent 70%)`,
              borderRadius: "50%",
            }}
          />
        )}
      </AnimatePresence>
    </motion.div>
  );
};
 
interface BlobConfig extends BlobProps {
  id: string;
}
 
interface BlobBackgroundProps {
  blobs?: BlobConfig[];
  className?: string;
}
 
const defaultBlobs: BlobConfig[] = [
  {
    id: "blob1",
    gradientColors: ["#FF0080", "#7928CA"],
    size: 400,
    blur: 60,
    speed: 15,
    opacity: 0.3,
    zIndex: 1,
    initialPosition: { x: 20, y: 20 },
    pulseScale: 1.2,
    rotationSpeed: 8,
  },
  {
    id: "blob2",
    gradientColors: ["#0070F3", "#00DFD8"],
    size: 300,
    blur: 50,
    speed: 20,
    opacity: 0.2,
    zIndex: 2,
    initialPosition: { x: 60, y: 60 },
    pulseScale: 1.15,
    rotationSpeed: 12,
  },
  {
    id: "blob3",
    gradientColors: ["#7928CA", "#FF0080"],
    size: 350,
    blur: 55,
    speed: 25,
    opacity: 0.25,
    zIndex: 3,
    initialPosition: { x: 80, y: 30 },
    pulseScale: 1.1,
    rotationSpeed: 10,
  },
];
 
export function BlobBackground({
  blobs = defaultBlobs,
  className = "",
}: BlobBackgroundProps) {
  return (
    <div
      className={`relative h-full w-full overflow-hidden ${className}`}
      style={{
        background: "transparent",
      }}
    >
      {blobs.map((blob) => (
        <Blob key={blob.id} {...blob} />
      ))}
    </div>
  );
}

Update the import paths to match your project setup.

import { BlobBackground } from "@/components/ui/blob-background";

Usage

import { BlobBackground } from "@/components/ui/blob-background";
 
export default function Example() {
  const blobs = [
    {
      id: "blob1",
      gradientColors: ["#7C3AED", "#EC4899"],
      size: 450,
      blur: 70,
      speed: 12,
      opacity: 0.3,
      zIndex: 1,
      initialPosition: { x: 30, y: 30 },
      pulseScale: 1.2,
      rotationSpeed: 8,
    },
    {
      id: "blob2",
      gradientColors: ["#EC4899", "#3B82F6"],
      size: 350,
      blur: 60,
      speed: 15,
      opacity: 0.25,
      zIndex: 2,
      initialPosition: { x: 70, y: 50 },
      pulseScale: 1.15,
      rotationSpeed: 12,
    },
  ];
 
  return (
    <div className="relative h-[400px] w-full">
      <BlobBackground blobs={blobs} />
    </div>
  );
}

Props

BlobBackground

NameTypeDefaultDescription
blobsBlob[][]Array of blob configurations
classNamestring""Additional CSS classes to apply to the container

Blob Configuration

NameTypeDefaultDescription
idstringRequiredUnique identifier for the blob
gradientColorsstring[]undefinedArray of colors for gradient background
colorstringundefinedSingle color for blob (used if gradientColors absent)
sizenumber400Size of the blob in pixels
blurnumber60Blur effect intensity
speednumber20Animation speed (lower is faster)
opacitynumber0.5Blob opacity
zIndexnumber0Z-index for layering blobs
initialPositionobject{x:50,y:50}Starting position in percentage
pulseScalenumber1.1Maximum scale during pulse animation
rotationSpeednumber10Rotation animation speed (lower is faster)