typescriptbeginner

Image Lazy Load Component

Lazy load images with a blur-up placeholder effect using Intersection Observer and CSS transitions.

typescript
import { useState, useRef, useEffect } from 'react';

export function LazyImage({
  src,
  alt,
  className = '',
}: {
  src: string;
  alt: string;
  className?: string;
}) {
  const [loaded, setLoaded] = useState(false);
  const [inView, setInView] = useState(false);
  const imgRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const node = imgRef.current;
    if (!node) return;
    const observer = new IntersectionObserver(
      ([entry]) => { if (entry.isIntersecting) { setInView(true); observer.disconnect(); } },
      { rootMargin: '200px' }
    );
    observer.observe(node);
    return () => observer.disconnect();
  }, []);

  return (
    <div ref={imgRef} className={className}>
      {inView && (
        <img
          src={src}
          alt={alt}
          onLoad={() => setLoaded(true)}
          style={{
            opacity: loaded ? 1 : 0,
            transition: 'opacity 0.3s ease-in',
          }}
        />
      )}
    </div>
  );
}

Use Cases

  • Image galleries
  • Blog post images
  • E-commerce product grids

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.