Love This UI? Help It Grow and Reach More Developers Worldwide

Noise Card Components

A collection of beautiful noise-textured cards with different color themes and interactive elements.

Deep Ocean Blue Card

Deep Ocean Blue

This card showcases the static noise effect on a deep ocean blue background.

Electric Purple Card

Electric Purple

This card showcases the static noise effect on an electric purple background.

Forest Green Card

Forest Green

This card showcases the static noise effect on a forest green background.

Classic Black Card

Classic Black

This card showcases the static noise effect on a classic black background.

Crimson Red Card

Crimson Red

This card showcases the static noise effect on a crimson red background.

Vibrant Orange Card

Vibrant Orange

This card showcases the static noise effect on a vibrant orange background.

Base Noise Card Component

tsxnoise-card.tsx
"use client";
import React, { useEffect, useRef, FC, ReactNode } from "react";

interface NoiseCardProps {
  width?: string;
  height?: string;
  children: ReactNode;
  className?: string;
  animated?: boolean;
  noiseOpacity?: number;
  grainSize?: number;
  bgColor?: string;
}

const NoiseCard: FC<NoiseCardProps> = ({
  width = "w-96",
  height = "h-72",
  children,
  className = "",
  animated = true,
  noiseOpacity = 0.1,
  grainSize = 1,
  bgColor = "bg-[#0014FF]",
}) => {
  const canvasRef = useRef<HTMLCanvasElement>(null);
  const containerRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const canvas = canvasRef.current;
    const container = containerRef.current;
    if (!canvas || !container) return;

    const ctx = canvas.getContext("2d");
    if (!ctx) return;

    let animationFrameId: number;

    const drawNoise = () => {
      const { width, height } = canvas;
      if (width === 0 || height === 0) return;

      if (grainSize === 1) {
        const imageData = ctx.createImageData(width, height);
        const data = imageData.data;
        const opacity = Math.floor(noiseOpacity * 255);

        for (let i = 0; i < data.length; i += 4) {
          const randomValue = Math.floor(Math.random() * 255);
          data[i] = randomValue;
          data[i + 1] = randomValue;
          data[i + 2] = randomValue;
          data[i + 3] = opacity;
        }

        ctx.putImageData(imageData, 0, 0);
      } else {
        ctx.clearRect(0, 0, width, height);
        for (let y = 0; y < height; y += grainSize) {
          for (let x = 0; x < width; x += grainSize) {
            const randomValue = Math.floor(Math.random() * 255);
            ctx.fillStyle = `rgba(${randomValue}, ${randomValue}, ${randomValue}, ${noiseOpacity})`;
            ctx.fillRect(x, y, grainSize, grainSize);
          }
        }
      }
    };

    const loop = () => {
      drawNoise();
      animationFrameId = requestAnimationFrame(loop);
    };

    const resizeObserver = new ResizeObserver((entries) => {
      for (const entry of entries) {
        const { width, height } = entry.contentRect;
        canvas.width = width;
        canvas.height = height;
        drawNoise();
      }
    });

    resizeObserver.observe(container);

    if (animated) {
      loop();
    } else {
      drawNoise();
    }

    return () => {
      if (animated) {
        cancelAnimationFrame(animationFrameId);
      }
      resizeObserver.disconnect();
    };
  }, [animated, noiseOpacity, grainSize]);

  return (
    <div
      ref={containerRef}
      className={`${width} ${height} ${bgColor} rounded-xl p-8 relative overflow-hidden ${className}`}
    >
      <canvas
        ref={canvasRef}
        className="absolute inset-0 w-full h-full pointer-events-none"
      />
      <div className="relative z-10 text-white h-full flex flex-col">
        {children}
      </div>
    </div>
  );
};

export default NoiseCard;