DEV Community

Jaimin Patel
Jaimin Patel

Posted on AI-assisted

How Responsive Images Work in React: srcSet, sizes, DPR and CDNs

If you have worked on a React application with a lot of images, you have probably seen this problem: the same large image gets downloaded on every device.

A desktop might display an image at 900px, while a mobile device only needs 350px. Sending the same 1600px image to both devices doesn't make much sense.

This is where responsive images help.

The browser can choose an appropriate image based on the image's display size and the device's pixel density. React doesn't need a special API for this — it uses the standard HTML image features.

Let's look at the main pieces.

Responsive Images in React

A basic React image is simple:

<img src="/images/product.jpg" alt="Product" />
Enter fullscreen mode Exit fullscreen mode

There is only one source here, so the browser downloads that image regardless of the screen size.

With responsive images, we can provide multiple versions:

<img
  src="/images/product-800.jpg"
  srcSet="
    /images/product-400.jpg 400w,
    /images/product-800.jpg 800w,
    /images/product-1200.jpg 1200w
  "
  alt="Product"
/>
Enter fullscreen mode Exit fullscreen mode

The 400w, 800w, and 1200w values tell the browser the actual width of each image.

But the browser also needs to know how large the image will be displayed. That's where sizes comes in.

srcSet and sizes

A simple way to remember them:

srcSet → What image versions are available?
sizes → How wide will the image be displayed?

For example:

<img
  src="/images/product-800.jpg"
  srcSet="
    /images/product-400.jpg 400w,
    /images/product-800.jpg 800w,
    /images/product-1200.jpg 1200w
  "
  sizes="(max-width: 768px) 100vw, 50vw"
  alt="Product"
/>
Enter fullscreen mode Exit fullscreen mode

Here, we're telling the browser that the image takes the full viewport width on smaller screens and roughly half the viewport width on larger screens.

If the desktop viewport is 1200px wide, the browser knows the image will be around 600px wide and can choose a suitable source.

That's the important part: srcSet provides choices, while sizes gives the browser information to make that choice.

DPR and High-Density Screens

Another factor is Device Pixel Ratio (DPR).

A device with a DPR of 2 has a higher pixel density than a standard 1x display. For a fixed-size image, you may want to provide a higher-resolution version.

For example:

<img
  src="/images/logo.png"
  srcSet="
    /images/logo.png 1x,
    /images/logo@2x.png 2x,
    /images/logo@3x.png 3x
  "
  alt="Logo"
/>
Enter fullscreen mode Exit fullscreen mode

This can be useful for:

Logos
Icons
Avatars
Other fixed-size images

For images that change size with the layout, width-based srcSet with sizes is generally the more useful approach.

So there are two common patterns:

Responsive layout → width-based srcSet + sizes

Fixed-size image → 1x / 2x / 3x

Where Does a CDN Fit?

If you have many images, manually creating every image size can become difficult.

Instead of maintaining:

product-400.jpg
product-800.jpg
product-1200.jpg

an image CDN can provide different sizes from the same source:

https://cdn.example.com/product.jpg?w=400
https://cdn.example.com/product.jpg?w=800
https://cdn.example.com/product.jpg?w=1200

You can then use those URLs in srcSet:

<img
  src="https://cdn.example.com/product.jpg?w=800"
  srcSet="
    https://cdn.example.com/product.jpg?w=400 400w,
    https://cdn.example.com/product.jpg?w=800 800w,
    https://cdn.example.com/product.jpg?w=1200 1200w
  "
  sizes="(max-width: 768px) 100vw, 50vw"
  alt="Product"
/>
Enter fullscreen mode Exit fullscreen mode

The responsibilities are different:

CDN → Provides the image variant.

srcSet → Tells the browser which variants are available.

sizes → Tells the browser the expected display width.

DPR → Accounts for the screen's pixel density.

A CDN can also provide different image formats such as WebP and AVIF, depending on the setup.

Using Responsive Images in React

If you don't want to manually handle all of these image-loading details in every component, a React image component can provide a higher-level API.

One example is React Smart Image, an open-source React image component I built. It provides responsive images along with features such as lazy loading, priority loading, WebP/AVIF support, blur placeholders, skeleton loaders, retry handling, fallback images, and zoom. It has zero runtime dependencies and works with React 18+.

For example:

import { SmartImage } from "@concatstring/react-smart-image";

<SmartImage
  src="/product.jpg"
  alt="Product"
  responsive
  lazy
/>
Enter fullscreen mode Exit fullscreen mode

It also supports combining responsive images with priority loading for important images such as hero images:

<SmartImage
  src="/hero.jpg"
  alt="Hero"
  responsive
  priority
/>
Enter fullscreen mode Exit fullscreen mode

The package is available on npm, and the project is open source on GitHub.

GitHub source code: https://github.com/concatstring-account/react-smart-image
NPM: https://www.npmjs.com/package/@concatstring/react-smart-image
Live demo: https://react-smart-image.netlify.app/

When Should You Use Each One?

There isn't one setup that works for every image.

Use srcSet

When the same image is displayed at different sizes depending on the layout.

Use sizes

When the rendered image width changes based on the viewport or layout. It works together with width-based srcSet.

Use DPR sources

When an image has a relatively fixed display size but needs to look sharp on high-density screens.

Use a CDN

When you have many images and need dynamic resizing, different formats, or different image variants.

Final Thoughts

Responsive images are not really a React-specific feature. React simply gives us a convenient way to use the browser's existing image capabilities.

The basic idea is straightforward:

srcSet → Available image sources

sizes → Expected display width

DPR → Screen pixel density

CDN → Image variants and transformations

For most responsive content images, start with srcSet + sizes.

For fixed-size assets, 1x/2x/3x DPR sources can be useful.

And if your application has a large image library, an image CDN can make managing those variants much easier.

The goal isn't to add every image feature available. It's to give the browser enough information to download an image that actually makes sense for the device and the layout.

Top comments (0)