Last updated: February 5, 2025

<span aria-hidden="true" id="implementing-lazy-loading-for-images-and-videos-in-react"></span>

# Implementing lazy loading for images and videos in React

![Tim Koschützki](/assets/images/teammates/avatar-tim-kos-1.jpg?dpl=dpl_B2d4XACVUtA1h8m6kRxZhWsda77Q)

#### Tim Koschützki

Co-founder · Berlin, Germany · Show bio

[](https://x.com/tim%5Fkos)[](https://github.com/tim-kos)

Improving web performance is crucial for delivering a smooth user experience. This tip demonstrates how to implement lazy loading for images and videos in React applications using modern best practices. Lazy loading defers non-critical resources until they are needed, reducing initial load times and conserving bandwidth.

<span aria-hidden="true" id="why-lazy-loading-matters"></span>

## Why lazy loading matters

Lazy loading defers the loading of non-critical resources until they are about to enter the viewport. By loading media only when it is needed, you reduce the data transferred during the initial load and improve performance on slow networks. This technique is especially beneficial for media-heavy pages.

<span aria-hidden="true" id="browser-support"></span>

## Browser support

Native lazy loading is now widely supported across modern browsers. In cases where a browser does not support the native attribute, a JavaScript fallback using the Intersection Observer API can be used:

* Chrome 77+
* Firefox 75+
* Safari 15.4+
* Edge 79+

<span aria-hidden="true" id="setting-up-a-react-application"></span>

## Setting up a React application

Start by creating a new React application with Create React App, which ensures you have the latest build configuration:

```bash
npx create-react-app@latest my-app
cd my-app
npm start

```

<span aria-hidden="true" id="implementing-lazy-loading-for-images"></span>

## Implementing lazy loading for images

<span aria-hidden="true" id="native-lazy-loading"></span>

### Native lazy loading

Modern browsers support native lazy loading via the `loading` attribute. This approach requires no additional JavaScript, simplifying your implementation:

```jsx
// Above the fold – load immediately
<img
  src="hero.jpg"
  alt="Hero image"
  width="800"
  height="600"
/>

// Below the fold – use native lazy loading
<img
  src="content.jpg"
  loading="lazy"
  alt="Content image"
  width="800"
  height="600"
/>

```

<span aria-hidden="true" id="advanced-lazy-loading-with-intersection-observer"></span>

### Advanced lazy loading with Intersection Observer

For more control in complex scenarios, use the Intersection Observer API via the`react-intersection-observer` library:

```bash
npm install react-intersection-observer@^9.15.1

```

```jsx
import { useInView } from 'react-intersection-observer'

function LazyImage({ src, alt, width, height }) {
  const { ref, inView } = useInView({
    triggerOnce: true,
    threshold: 0.1,
  })

  return (
    <div
      ref={ref}
      style={
        {
          width,
          height,
          background: '#f0f0f0'
        }
      }
    >
      {inView ? (
        <img
          src={src}
          alt={alt}
          width={width}
          height={height}
          style={
            {
              width: '100%',
              height: '100%',
              objectFit: 'cover'
            }
          }
        />
      ) : null}
    </div>
  )
}

```

<span aria-hidden="true" id="implementing-lazy-loading-for-videos"></span>

## Implementing lazy loading for videos

<span aria-hidden="true" id="using-react-suspense"></span>

### Using React suspense

For component-level lazy loading, employ React's built-in `Suspense` feature to defer the loading of video components:

```jsx
import React, { Suspense } from 'react'

const VideoPlayer = React.lazy(() => import('./VideoPlayer'))

function App() {
  return (
    <Suspense fallback={<div>Loading video player...</div>}>
      <VideoPlayer />
    </Suspense>
  )
}

```

<span aria-hidden="true" id="lazy-loading-video-content"></span>

### Lazy loading video content

Apply lazy loading to the video content itself using the Intersection Observer API:

```jsx
import { useInView } from 'react-intersection-observer'

function LazyVideo({ src, poster }) {
  const { ref, inView } = useInView({
    triggerOnce: true,
    threshold: 0.1,
  })

  return (
    <div ref={ref}>
      {inView ? (
        <video
          controls
          preload="none"
          poster={poster}
          style={{ maxWidth: '100%' }}
        >
          <source src={src} type="video/mp4" />
          Your browser does not support the video tag.
        </video>
      ) : (
        <img
          src={poster}
          alt="Video thumbnail"
          style={{ maxWidth: '100%' }}
        />
      )}
    </div>
  )
}

```

<span aria-hidden="true" id="performance-best-practices"></span>

## Performance best practices

* Eager-load content above the fold to ensure a fast initial render.
* Always provide explicit width and height attributes to prevent layout shifts.
* Use modern image formats such as WebP with appropriate fallbacks.
* Implement responsive images using `srcset` and `sizes` for different device widths:

```jsx
<img
  src="image-800w.jpg"
  srcset="
    image-400w.jpg 400w,
    image-800w.jpg 800w,
    image-1200w.jpg 1200w
  "
  sizes="(max-width: 400px) 400px,
         (max-width: 800px) 800px,
         1200px"
  loading="lazy"
  alt="Responsive image"
/>

```

<span aria-hidden="true" id="optimizing-photo-delivery-with-cloudflare-image-cdn"></span>

## Optimizing photo delivery with Cloudflare image CDN

In addition to lazy loading, using a Content Delivery Network (CDN) can further boost your application's performance by optimizing how photos are delivered. Cloudflare Image CDN automatically resizes, compresses, and optimizes images, ensuring faster load times and reduced bandwidth consumption—ideal for handling cdn fotos.

Follow these steps to integrate Cloudflare Image CDN into your React application:

1. Sign up for a Cloudflare account and add your domain.
2. Enable Cloudflare's Image Resizing feature and configure the desired parameters (such as width and quality).
3. Update your image URLs to route through Cloudflare. For example:

```jsx
<img
  src="https://your-domain.com/cdn-cgi/image/width=800,quality=80/yourimage.jpg"
  alt="Optimized image"
  loading="lazy"
  width="800"
  height="600"
/>

```

This setup leverages the power of Cloudflare Image CDN—one of the best image cdn solutions—to further enhance image optimization and improve load speeds across devices.

<span aria-hidden="true" id="monitoring-and-debugging"></span>

## Monitoring and debugging

Use Chrome DevTools to monitor lazy loading and diagnose performance issues:

1. Open the Network tab and filter by "Img" or "Media".
2. Scroll the page to observe when resources load.
3. Use the Performance tab to measure impact and check for layout shifts.

<span aria-hidden="true" id="conclusion"></span>

## Conclusion

Combining lazy loading with CDN-based image optimization significantly improves web performance by deferring non-critical resource loads and delivering media efficiently. For additional media handling and processing, consider using Transloadit's comprehensive services to complement your implementation.

\#react#lazy-loading#image-optimization#web-performance

### 👩‍💻 Join 20k+ developers

Sign up for our [monthly newsletter](/newsletters.md) to receive direct links to 3 exclusive tech — and 2 product updates. No less, no more.

Your email:

Get access

## File uploading and encoding. Made simple.

Transloadit streamlines file handling for developers, trusted by brands like Coursera and The New York Times. We’re known for a reliable API, top-notch support, and a strong commitment to open source, with projects like [Uppy⁠](https://uppy.io) and [Tus⁠](https://tus.io) setting standards in file processing.

[Sign up](/c/)[Book a Demo](https://survey.typeform.com/to/kRg47Xi5)

No credit card needed · 5 GB included in the free plan

Cancel anytime
