<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jaimin Patel</title>
    <description>The latest articles on DEV Community by Jaimin Patel (@jaimin_patel).</description>
    <link>https://dev.to/jaimin_patel</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4010501%2F012fcc83-4920-4029-ab2f-be88699bc851.png</url>
      <title>DEV Community: Jaimin Patel</title>
      <link>https://dev.to/jaimin_patel</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jaimin_patel"/>
    <language>en</language>
    <item>
      <title>How Responsive Images Work in React: srcSet, sizes, DPR and CDNs</title>
      <dc:creator>Jaimin Patel</dc:creator>
      <pubDate>Tue, 22 Sep 2026 13:30:00 +0000</pubDate>
      <link>https://dev.to/jaimin_patel/how-responsive-images-work-in-react-srcset-sizes-dpr-and-cdns-1ocf</link>
      <guid>https://dev.to/jaimin_patel/how-responsive-images-work-in-react-srcset-sizes-dpr-and-cdns-1ocf</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkj7u8q51goj66kx4anwb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkj7u8q51goj66kx4anwb.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;This is where responsive images help.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Let's look at the main pieces.&lt;/p&gt;

&lt;h2&gt;
  
  
  Responsive Images in React
&lt;/h2&gt;

&lt;p&gt;A basic React image is simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/images/product.jpg"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Product"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is only one source here, so the browser downloads that image regardless of the screen size.&lt;/p&gt;

&lt;p&gt;With responsive images, we can provide multiple versions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt;
  &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/images/product-800.jpg"&lt;/span&gt;
  &lt;span class="na"&gt;srcSet=&lt;/span&gt;&lt;span class="s"&gt;"
    /images/product-400.jpg 400w,
    /images/product-800.jpg 800w,
    /images/product-1200.jpg 1200w
  "&lt;/span&gt;
  &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Product"&lt;/span&gt;
&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The 400w, 800w, and 1200w values tell the browser the actual width of each image.&lt;/p&gt;

&lt;p&gt;But the browser also needs to know how large the image will be displayed. That's where sizes comes in.&lt;/p&gt;

&lt;h2&gt;
  
  
  srcSet and sizes
&lt;/h2&gt;

&lt;p&gt;A simple way to remember them:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;srcSet&lt;/strong&gt; → What image versions are available?&lt;br&gt;
&lt;strong&gt;sizes&lt;/strong&gt; → How wide will the image be displayed?&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt;
  &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/images/product-800.jpg"&lt;/span&gt;
  &lt;span class="na"&gt;srcSet=&lt;/span&gt;&lt;span class="s"&gt;"
    /images/product-400.jpg 400w,
    /images/product-800.jpg 800w,
    /images/product-1200.jpg 1200w
  "&lt;/span&gt;
  &lt;span class="na"&gt;sizes=&lt;/span&gt;&lt;span class="s"&gt;"(max-width: 768px) 100vw, 50vw"&lt;/span&gt;
  &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Product"&lt;/span&gt;
&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;If the desktop viewport is 1200px wide, the browser knows the image will be around 600px wide and can choose a suitable source.&lt;/p&gt;

&lt;p&gt;That's the important part: &lt;strong&gt;srcSet provides choices, while sizes gives the browser information to make that choice.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  DPR and High-Density Screens
&lt;/h2&gt;

&lt;p&gt;Another factor is &lt;strong&gt;Device Pixel Ratio (DPR)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt;
  &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/images/logo.png"&lt;/span&gt;
  &lt;span class="na"&gt;srcSet=&lt;/span&gt;&lt;span class="s"&gt;"
    /images/logo.png 1x,
    /images/logo@2x.png 2x,
    /images/logo@3x.png 3x
  "&lt;/span&gt;
  &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Logo"&lt;/span&gt;
&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This can be useful for:&lt;/p&gt;

&lt;p&gt;Logos&lt;br&gt;
Icons&lt;br&gt;
Avatars&lt;br&gt;
Other fixed-size images&lt;/p&gt;

&lt;p&gt;For images that change size with the layout, width-based srcSet with sizes is generally the more useful approach.&lt;/p&gt;

&lt;p&gt;So there are two common patterns:&lt;/p&gt;

&lt;p&gt;Responsive layout → width-based srcSet + sizes&lt;/p&gt;

&lt;p&gt;Fixed-size image → 1x / 2x / 3x&lt;/p&gt;
&lt;h2&gt;
  
  
  Where Does a CDN Fit?
&lt;/h2&gt;

&lt;p&gt;If you have many images, manually creating every image size can become difficult.&lt;/p&gt;

&lt;p&gt;Instead of maintaining:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;product-400.jpg&lt;br&gt;
product-800.jpg&lt;br&gt;
product-1200.jpg&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;an image CDN can provide different sizes from the same source:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://cdn.example.com/product.jpg?w=400" rel="noopener noreferrer"&gt;https://cdn.example.com/product.jpg?w=400&lt;/a&gt;&lt;br&gt;
&lt;a href="https://cdn.example.com/product.jpg?w=800" rel="noopener noreferrer"&gt;https://cdn.example.com/product.jpg?w=800&lt;/a&gt;&lt;br&gt;
&lt;a href="https://cdn.example.com/product.jpg?w=1200" rel="noopener noreferrer"&gt;https://cdn.example.com/product.jpg?w=1200&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can then use those URLs in srcSet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt;
  &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.example.com/product.jpg?w=800"&lt;/span&gt;
  &lt;span class="na"&gt;srcSet=&lt;/span&gt;&lt;span class="s"&gt;"
    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
  "&lt;/span&gt;
  &lt;span class="na"&gt;sizes=&lt;/span&gt;&lt;span class="s"&gt;"(max-width: 768px) 100vw, 50vw"&lt;/span&gt;
  &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Product"&lt;/span&gt;
&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The responsibilities are different:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CDN&lt;/strong&gt; → Provides the image variant.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;srcSet&lt;/strong&gt; → Tells the browser which variants are available.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;sizes&lt;/strong&gt; → Tells the browser the expected display width.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DPR&lt;/strong&gt; → Accounts for the screen's pixel density.&lt;/p&gt;

&lt;p&gt;A CDN can also provide different image formats such as WebP and AVIF, depending on the setup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Responsive Images in React
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;One example is &lt;a href="https://www.npmjs.com/package/@concatstring/react-smart-image" rel="noopener noreferrer"&gt;React Smart Image&lt;/a&gt;, 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+.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SmartImage&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@concatstring/react-smart-image&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SmartImage&lt;/span&gt;
  &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/product.jpg"&lt;/span&gt;
  &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Product"&lt;/span&gt;
  &lt;span class="na"&gt;responsive&lt;/span&gt;
  &lt;span class="na"&gt;lazy&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It also supports combining responsive images with priority loading for important images such as hero images:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SmartImage&lt;/span&gt;
  &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/hero.jpg"&lt;/span&gt;
  &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Hero"&lt;/span&gt;
  &lt;span class="na"&gt;responsive&lt;/span&gt;
  &lt;span class="na"&gt;priority&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The package is available on npm, and the project is open source on GitHub.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://labs.concatstring.com/products/react-smart-image" rel="noopener noreferrer"&gt;&lt;strong&gt;Website:&lt;/strong&gt; https://labs.concatstring.com/products/react-smart-image&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/concatstring-account/react-smart-image" rel="noopener noreferrer"&gt;&lt;strong&gt;GitHub Source Code:&lt;/strong&gt; https://github.com/concatstring-account/react-smart-image&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.npmjs.com/package/@concatstring/react-smart-image" rel="noopener noreferrer"&gt;&lt;strong&gt;NPM:&lt;/strong&gt; https://www.npmjs.com/package/@concatstring/react-smart-image&lt;/a&gt;&lt;br&gt;
&lt;a href="https://react-smart-image.netlify.app/" rel="noopener noreferrer"&gt;&lt;strong&gt;Live Demo:&lt;/strong&gt; https://react-smart-image.netlify.app/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  When Should You Use Each One?
&lt;/h2&gt;

&lt;p&gt;There isn't one setup that works for every image.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use srcSet&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When the same image is displayed at different sizes depending on the layout.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use sizes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When the rendered image width changes based on the viewport or layout. It works together with width-based srcSet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use DPR sources&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When an image has a relatively fixed display size but needs to look sharp on high-density screens.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use a CDN&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When you have many images and need dynamic resizing, different formats, or different image variants.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

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

&lt;p&gt;The basic idea is straightforward:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;srcSet&lt;/strong&gt; → Available image sources&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;sizes&lt;/strong&gt;  → Expected display width&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DPR&lt;/strong&gt;    → Screen pixel density&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CDN&lt;/strong&gt;    → Image variants and transformations&lt;/p&gt;

&lt;p&gt;For most responsive content images, start with &lt;strong&gt;srcSet + sizes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For fixed-size assets, &lt;strong&gt;1x/2x/3x DPR sources&lt;/strong&gt; can be useful.&lt;/p&gt;

&lt;p&gt;And if your application has a large image library, an image CDN can make managing those variants much easier.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>performance</category>
      <category>frontend</category>
    </item>
    <item>
      <title>WebP vs AVIF: Which Image Format Is Better for React?</title>
      <dc:creator>Jaimin Patel</dc:creator>
      <pubDate>Mon, 14 Sep 2026 18:10:16 +0000</pubDate>
      <link>https://dev.to/jaimin_patel/webp-vs-avif-which-image-format-is-better-for-react-2bol</link>
      <guid>https://dev.to/jaimin_patel/webp-vs-avif-which-image-format-is-better-for-react-2bol</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftacyg2df4w9632rgvk7m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftacyg2df4w9632rgvk7m.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you are working on a React application, images are usually one of the first things I look at when trying to improve page performance.&lt;/p&gt;

&lt;p&gt;A large JPEG or PNG image can easily be hundreds of KB or even a few MB. If a page contains multiple images, that can quickly increase the amount of data the browser needs to download.&lt;/p&gt;

&lt;p&gt;This is where modern image formats like WebP and AVIF become useful.&lt;/p&gt;

&lt;p&gt;Both formats can reduce image size compared with traditional JPEG and PNG images, but they have some differences.&lt;/p&gt;

&lt;p&gt;So, which one should you use in a React project?&lt;/p&gt;

&lt;p&gt;Let's look at the practical differences.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is WebP?
&lt;/h2&gt;

&lt;p&gt;WebP is an image format developed by Google.&lt;/p&gt;

&lt;p&gt;The main goal of WebP is simple: provide smaller image files without losing too much visual quality.&lt;/p&gt;

&lt;p&gt;WebP supports both lossy and lossless compression, as well as transparency and animation.&lt;/p&gt;

&lt;p&gt;The actual size will depend on the original image and compression settings, but WebP can provide a significant reduction compared with JPEG.&lt;/p&gt;

&lt;p&gt;One reason WebP became popular is that browser support became very good, making it a practical replacement for many JPEG and PNG images.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is AVIF?
&lt;/h2&gt;

&lt;p&gt;AVIF is a newer image format based on the AV1 video codec.&lt;/p&gt;

&lt;p&gt;Its biggest advantage is compression efficiency.&lt;/p&gt;

&lt;p&gt;In many cases, AVIF can produce a smaller file than WebP while maintaining similar visual quality.&lt;/p&gt;

&lt;p&gt;If your website contains a lot of photographs or large images, reducing the file size can save a significant amount of bandwidth.&lt;/p&gt;

&lt;p&gt;The downside is that AVIF encoding can sometimes require more processing than WebP, depending on the encoder and configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  WebP vs AVIF: File Size
&lt;/h2&gt;

&lt;p&gt;If we compare compression efficiency, AVIF will often produce a smaller file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For example:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Original JPEG: 800 KB&lt;br&gt;
WebP:          500 KB&lt;br&gt;
AVIF:          350 KB&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Imagine a product page with 20 images.&lt;/p&gt;

&lt;p&gt;Even a small reduction per image can make a noticeable difference in the total amount of data downloaded.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This is especially useful for:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;E-commerce websites&lt;br&gt;
Photography websites&lt;br&gt;
News websites&lt;br&gt;
Blogs with many images&lt;br&gt;
Image-heavy React applications&lt;/p&gt;

&lt;p&gt;However, smaller file size isn't the only thing that matters.&lt;/p&gt;

&lt;p&gt;You also need to consider image quality, browser support and how easily you can generate these formats.&lt;/p&gt;
&lt;h2&gt;
  
  
  Browser Support
&lt;/h2&gt;

&lt;p&gt;Browser support is another important difference.&lt;/p&gt;

&lt;p&gt;WebP has been supported by modern browsers for quite a while, so it is generally a safe choice.&lt;/p&gt;

&lt;p&gt;AVIF also has broad support in modern browsers, but if your application needs to support older browsers or different environments, providing a fallback is still a good idea.&lt;/p&gt;

&lt;p&gt;One common approach is using the  element:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;picture&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;source&lt;/span&gt; &lt;span class="na"&gt;srcSet=&lt;/span&gt;&lt;span class="s"&gt;"/images/photo.avif"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"image/avif"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;source&lt;/span&gt; &lt;span class="na"&gt;srcSet=&lt;/span&gt;&lt;span class="s"&gt;"/images/photo.webp"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"image/webp"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt;
    &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/images/photo.jpg"&lt;/span&gt;
    &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Example"&lt;/span&gt;
  &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/picture&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The browser will choose the first supported format.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So the fallback can look like:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;AVIF&lt;br&gt;
  ↓&lt;br&gt;
WebP&lt;br&gt;
  ↓&lt;br&gt;
JPEG&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This approach lets you use AVIF for browsers that support it while still having a WebP or JPEG fallback.&lt;/p&gt;

&lt;h2&gt;
  
  
  What About Image Quality?
&lt;/h2&gt;

&lt;p&gt;Both WebP and AVIF can provide very good image quality.&lt;/p&gt;

&lt;p&gt;But the format itself isn't the only factor.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The final result depends on things like:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Compression level&lt;br&gt;
Encoder&lt;br&gt;
Image type&lt;br&gt;
Original image quality&lt;br&gt;
Image dimensions&lt;/p&gt;

&lt;p&gt;For example, an aggressively compressed AVIF image can look worse than a properly compressed WebP image.&lt;/p&gt;

&lt;p&gt;So I wouldn't simply say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;AVIF is better because it is smaller.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A better question is: &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which format gives you the image quality you need at the file size you want?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For large photographs, AVIF can be very effective.&lt;/p&gt;

&lt;p&gt;For general website images, WebP may already provide more than enough compression and quality.&lt;/p&gt;
&lt;h2&gt;
  
  
  Using WebP and AVIF in React
&lt;/h2&gt;

&lt;p&gt;Using modern image formats is only one part of image optimization in React.&lt;/p&gt;

&lt;p&gt;For example, you could have a perfectly optimized AVIF image, but if you're loading a 2000px image into a 400px container, you're still downloading more data than necessary.&lt;/p&gt;

&lt;p&gt;Responsive images are important too.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt;
  &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/images/product-800.webp"&lt;/span&gt;
  &lt;span class="na"&gt;srcSet=&lt;/span&gt;&lt;span class="s"&gt;"
    /images/product-400.webp 400w,
    /images/product-800.webp 800w,
    /images/product-1200.webp 1200w
  "&lt;/span&gt;
  &lt;span class="na"&gt;sizes=&lt;/span&gt;&lt;span class="s"&gt;"(max-width: 768px) 100vw, 800px"&lt;/span&gt;
  &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Product"&lt;/span&gt;
&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the browser can select an appropriate image size based on the user's device and layout.&lt;/p&gt;

&lt;p&gt;You can also combine responsive images with AVIF and WebP using&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;picture&amp;gt;&lt;/span&gt;.

For example:

&lt;span class="nt"&gt;&amp;lt;picture&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;source&lt;/span&gt;
    &lt;span class="na"&gt;srcSet=&lt;/span&gt;&lt;span class="s"&gt;"/images/product.avif"&lt;/span&gt;
    &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"image/avif"&lt;/span&gt;
  &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;source&lt;/span&gt;
    &lt;span class="na"&gt;srcSet=&lt;/span&gt;&lt;span class="s"&gt;"/images/product.webp"&lt;/span&gt;
    &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"image/webp"&lt;/span&gt;
  &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt;
    &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/images/product.jpg"&lt;/span&gt;
    &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Product"&lt;/span&gt;
  &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/picture&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives you a practical fallback strategy without forcing every browser to use the same format.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;So, WebP vs AVIF — which one is better?&lt;/p&gt;

&lt;p&gt;There isn't a single answer for every React application.&lt;/p&gt;

&lt;p&gt;WebP is mature, reliable and provides good compression with broad browser support.&lt;/p&gt;

&lt;p&gt;AVIF can provide even better compression and smaller files, especially for photographs and image-heavy websites.&lt;/p&gt;

&lt;p&gt;If your project supports it, using both can be a practical approach:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;AVIF&lt;br&gt;
 ↓&lt;br&gt;
WebP&lt;br&gt;
 ↓&lt;br&gt;
JPEG/PNG&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But don't forget that image optimization is bigger than just choosing a file format.&lt;/p&gt;

&lt;p&gt;Test your real images, check the file sizes, compare the visual quality, and measure the actual loading performance.&lt;/p&gt;

&lt;p&gt;That's usually the best way to decide.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related React Smart Image NPM
&lt;/h2&gt;

&lt;p&gt;I also created &lt;strong&gt;&lt;a href="https://www.npmjs.com/package/@concatstring/react-smart-image" rel="noopener noreferrer"&gt;@concatstring/react-smart-image&lt;/a&gt;&lt;/strong&gt; for React applications. It can automatically try AVIF → WebP → the original image when those formats are available.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;SmartImage&lt;/span&gt;
  &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/images/banner.jpg"&lt;/span&gt;
  &lt;span class="na"&gt;format=&lt;/span&gt;&lt;span class="s"&gt;"auto"&lt;/span&gt;
  &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Banner"&lt;/span&gt;
&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your CDN or image storage provides the corresponding files:&lt;/p&gt;

&lt;p&gt;banner.avif → banner.webp → banner.jpg&lt;/p&gt;

&lt;p&gt;You can also use it with image services such as Cloudinary or other CDNs that provide optimized image formats.&lt;/p&gt;

&lt;p&gt;The package doesn't convert the images itself. It simply uses the available AVIF/WebP versions and falls back to the original image when needed.&lt;/p&gt;

&lt;p&gt;Check it out:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NPM:&lt;/strong&gt; &lt;a href="https://www.npmjs.com/package/@concatstring/react-smart-image" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/@concatstring/react-smart-image&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/concatstring-account/react-smart-image" rel="noopener noreferrer"&gt;https://github.com/concatstring-account/react-smart-image&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Demo:&lt;/strong&gt; &lt;a href="https://react-smart-image.netlify.app/" rel="noopener noreferrer"&gt;https://react-smart-image.netlify.app/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>performance</category>
    </item>
    <item>
      <title>How I Made My React Website Load Faster by Fixing Images</title>
      <dc:creator>Jaimin Patel</dc:creator>
      <pubDate>Mon, 07 Sep 2026 19:28:55 +0000</pubDate>
      <link>https://dev.to/jaimin_patel/how-i-made-my-react-website-load-faster-by-fixing-images-2n1d</link>
      <guid>https://dev.to/jaimin_patel/how-i-made-my-react-website-load-faster-by-fixing-images-2n1d</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpuskh7xzrfgnoqccnfu3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpuskh7xzrfgnoqccnfu3.png" alt="Top of post" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The easiest performance win in React isn't always your JavaScript. Sometimes it's your images.&lt;/p&gt;

&lt;p&gt;I used to think performance optimization meant splitting bundles, memoizing components, and chasing Lighthouse scores.&lt;/p&gt;

&lt;p&gt;Then I opened Chrome DevTools on one of my own React projects.&lt;/p&gt;

&lt;p&gt;The result? Images were quietly eating most of the page weight — way more than my JS bundle, my fonts, everything else combined.&lt;/p&gt;

&lt;p&gt;A hero banner that looked perfect on my laptop was making mobile users download a multi-megabyte file just to see a heading.&lt;/p&gt;

&lt;p&gt;That's when it clicked: image optimization isn't a nice-to-have. It's one of the fastest ways to make a React site actually feel faster.&lt;/p&gt;

&lt;p&gt;Here's exactly what I changed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Image Optimization Matters&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every extra second of load time costs you something — a visitor who bounces, a search ranking that slips, a bandwidth bill that keeps climbing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhbod6c9ghard6ziogasg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhbod6c9ghard6ziogasg.png" alt="Why Image Optimization Matters" width="800" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;None of that is dramatic on its own. But it adds up fast, and images are usually where it's hiding.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;First Rule: Stop Uploading Giant Images&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We've all done it.&lt;/p&gt;

&lt;p&gt;Designer sends a beautiful 4000×3000 image.&lt;/p&gt;

&lt;p&gt;We drop it into React.&lt;/p&gt;

&lt;p&gt;Then display it inside a 400px card.&lt;/p&gt;

&lt;p&gt;The browser still downloads the full file — every pixel of it, whether you show it or not.&lt;/p&gt;

&lt;p&gt;Instead, match your image size to where it's actually displayed:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Device&lt;/th&gt;
&lt;th&gt;Image Width&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Mobile&lt;/td&gt;
&lt;td&gt;400px&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tablet&lt;/td&gt;
&lt;td&gt;800px&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Desktop&lt;/td&gt;
&lt;td&gt;1200px&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Your users won't notice the difference in quality. They'll definitely notice the faster loading.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Two Formats I Use for Almost Every Project&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxxfxygxcus2chbupfz1p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxxfxygxcus2chbupfz1p.png" alt="The Two Formats I Use for Almost Every Project" width="800" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;WebP — if you're still serving JPEGs everywhere, you're leaving free performance on the table. WebP usually keeps the same visual quality while shrinking the file size significantly.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;p&gt;JPEG → 500KB&lt;br&gt;
WebP → around 320KB&lt;/p&gt;

&lt;p&gt;That's hundreds of kilobytes saved without changing your design at all.&lt;/p&gt;

&lt;p&gt;AVIF — takes compression even further. I've seen hero images drop from 500KB to nearly 200KB with almost no visible quality loss. Browser support is good enough now that it's worth using wherever you can.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lazy Loading Is Basically Free Performance&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One thing I always ask myself now: "Does this image need to load immediately?"&lt;/p&gt;

&lt;p&gt;Usually the answer is no.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4bn93n167rd8fm8xwwwl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4bn93n167rd8fm8xwwwl.png" alt="Lazy Loading Is Basically Free Performance" width="800" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Gallery images. Blog thumbnails. Testimonials. Footer logos. All of these can wait until users actually scroll near them.&lt;/p&gt;

&lt;p&gt;React makes it ridiculously simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt;
  &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/gallery/photo.webp"&lt;/span&gt;
  &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Gallery"&lt;/span&gt;
  &lt;span class="na"&gt;loading=&lt;/span&gt;&lt;span class="s"&gt;"lazy"&lt;/span&gt;
&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One attribute. Less network traffic. Faster initial load.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But Don't Lazy Load Everything&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Your hero image is different. If it's the biggest thing users see first, load it immediately — not lazily.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Hero Image Can Make or Break Your LCP&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Google's Largest Contentful Paint (LCP) is often just your hero image, plain and simple.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgcosod2wr22kdajpkf1h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgcosod2wr22kdajpkf1h.png" alt="The Hero Image Can Make or Break Your LCP" width="800" height="498"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If it's delayed, your performance score suffers. Instead of this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/hero.webp"&lt;/span&gt; &lt;span class="na"&gt;loading=&lt;/span&gt;&lt;span class="s"&gt;"lazy"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt;
  &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/hero.webp"&lt;/span&gt;
  &lt;span class="na"&gt;loading=&lt;/span&gt;&lt;span class="s"&gt;"eager"&lt;/span&gt;
  &lt;span class="na"&gt;fetchPriority=&lt;/span&gt;&lt;span class="s"&gt;"high"&lt;/span&gt;
  &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Hero"&lt;/span&gt;
&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Small change. But now the browser knows this image deserves priority over everything else on the page.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Page Jump Problem (CLS)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Have you ever tried clicking something and the page suddenly moved because an image loaded underneath your cursor?&lt;/p&gt;

&lt;p&gt;That's Cumulative Layout Shift. The browser didn't know how much space to reserve, so it grabbed space the moment the image arrived — shoving everything else out of the way.&lt;/p&gt;

&lt;p&gt;Bad:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/product.jpg"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Product"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Better:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt;
  &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/product.jpg"&lt;/span&gt;
  &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Product"&lt;/span&gt;
  &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or use CSS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.product-image&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;aspect-ratio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the layout stays stable while the image loads, no matter how slow the connection is.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mobile Users Don't Need Desktop Images&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is probably the biggest missed opportunity I see in React codebases.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fywhop6xl38rikew2c1e0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fywhop6xl38rikew2c1e0.png" alt="Mobile Users Don't Need Desktop Images" width="799" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Why send a 1200px image to someone on a 390px phone? That's exactly why srcSet exists:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt;
  &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/image-800.webp"&lt;/span&gt;
  &lt;span class="na"&gt;srcSet=&lt;/span&gt;&lt;span class="s"&gt;"
    /image-400.webp 400w,
    /image-800.webp 800w,
    /image-1200.webp 1200w
  "&lt;/span&gt;
  &lt;span class="na"&gt;sizes=&lt;/span&gt;&lt;span class="s"&gt;"(max-width: 768px) 100vw, 800px"&lt;/span&gt;
  &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Responsive"&lt;/span&gt;
&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The browser automatically picks the right version. No complicated logic. No JavaScript required.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Image Component I Kept Rebuilding&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After repeating these optimizations across multiple projects, I noticed I was writing the same image component again and again. Every project needed:&lt;/p&gt;

&lt;p&gt;Lazy loading&lt;br&gt;
Blur placeholders&lt;br&gt;
Skeleton loaders&lt;br&gt;
WebP support&lt;br&gt;
AVIF support&lt;br&gt;
Priority loading for hero images&lt;br&gt;
Aspect ratio to prevent CLS&lt;/p&gt;

&lt;p&gt;So I turned it into a reusable package.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;React Smart Image&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Instead of wiring everything manually, I can now just write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SmartImage&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@concatstring/react-smart-image&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SmartImage&lt;/span&gt;
  &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/hero.webp"&lt;/span&gt;
  &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Hero"&lt;/span&gt;
  &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1200&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;700&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;priority&lt;/span&gt;
  &lt;span class="na"&gt;aspectRatio&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"12:7"&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It handles most of these best practices automatically — which saves real time, especially on bigger React projects with hundreds of images scattered across pages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My Go-To Image Optimization Checklist&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Before shipping any React page, I run through this quickly:&lt;/p&gt;

&lt;p&gt;Resize images before uploading&lt;br&gt;
Use WebP or AVIF whenever possible&lt;br&gt;
Lazy load below-the-fold images&lt;br&gt;
Prioritize the hero image&lt;br&gt;
Set width and height (or aspect ratio)&lt;br&gt;
Use srcSet for responsive images&lt;/p&gt;

&lt;p&gt;Five minutes on this list usually saves users several seconds of loading time. Honestly, it's one of the highest-ROI optimizations I've found in React — full stop.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try React Smart Image&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you don't want to configure every image manually, check out the package I built.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;React Smart Image&lt;/strong&gt; — lazy loading, blur placeholders, skeleton loaders, WebP &amp;amp; AVIF support, LCP priority loading, responsive images, and CLS prevention, all in one component.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NPM Package:&lt;/strong&gt; &lt;a href="https://www.npmjs.com/package/@concatstring/react-smart-image" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/@concatstring/react-smart-image&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/concatstring-account/react-smart-image" rel="noopener noreferrer"&gt;https://github.com/concatstring-account/react-smart-image&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Live Demo:&lt;/strong&gt; &lt;a href="https://react-smart-image.netlify.app/" rel="noopener noreferrer"&gt;https://react-smart-image.netlify.app/&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Product Page:&lt;/strong&gt; &lt;a href="https://labs.concatstring.com/products/react-smart-image" rel="noopener noreferrer"&gt;https://labs.concatstring.com/products/react-smart-image&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you're building React apps regularly, these small image optimizations add up — and your users (and your Lighthouse score) will thank you for it.&lt;/p&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>performance</category>
    </item>
    <item>
      <title>React Lazy Loading Images: A Simple Guide to Better Performance</title>
      <dc:creator>Jaimin Patel</dc:creator>
      <pubDate>Mon, 31 Aug 2026 18:40:39 +0000</pubDate>
      <link>https://dev.to/jaimin_patel/react-lazy-loading-images-a-simple-guide-to-better-performance-48hh</link>
      <guid>https://dev.to/jaimin_patel/react-lazy-loading-images-a-simple-guide-to-better-performance-48hh</guid>
      <description>&lt;p&gt;Images are important for modern websites, but loading too many images at once can slow down a React application.&lt;/p&gt;

&lt;p&gt;If a page contains 30 images, users may only see 4–5 of them initially. There is no reason to load all 30 images immediately.&lt;/p&gt;

&lt;p&gt;That's where &lt;strong&gt;lazy loading&lt;/strong&gt; helps.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is Lazy Loading?
&lt;/h2&gt;

&lt;p&gt;Lazy loading means &lt;strong&gt;delaying the loading of an image until it is needed&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Instead of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Page loads
↓
Load every image
↓
Show page
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lazy loading works more like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Page loads
↓
Load visible images
↓
User scrolls
↓
Load images near the viewport
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This can reduce unnecessary network requests and improve the initial loading experience.&lt;/p&gt;

&lt;p&gt;For more information, see the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Performance/Guides/Lazy_loading" rel="noopener noreferrer"&gt;MDN Lazy Loading Guide&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does Lazy Loading Improve Performance?
&lt;/h2&gt;

&lt;p&gt;Images can be large and consume a significant amount of bandwidth.&lt;/p&gt;

&lt;p&gt;Lazy loading helps by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reducing initial network requests&lt;/li&gt;
&lt;li&gt;Reducing bandwidth usage&lt;/li&gt;
&lt;li&gt;Loading important content sooner&lt;/li&gt;
&lt;li&gt;Improving the experience on slower connections&lt;/li&gt;
&lt;li&gt;Avoiding downloads for images the user never views&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, lazy loading does &lt;strong&gt;not&lt;/strong&gt; make the image file smaller. You should still optimize image dimensions, compression, and formats such as WebP or AVIF&lt;/p&gt;

&lt;h2&gt;
  
  
  Native Lazy Loading
&lt;/h2&gt;

&lt;p&gt;Modern browsers support native lazy loading through the &lt;code&gt;loading&lt;/code&gt; attribute.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt;
  &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/images/product.jpg"&lt;/span&gt;
  &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Product"&lt;/span&gt;
  &lt;span class="na"&gt;loading=&lt;/span&gt;&lt;span class="s"&gt;"lazy"&lt;/span&gt;
&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The browser decides when to load the image based on its distance from the viewport.&lt;/p&gt;

&lt;p&gt;This is usually the simplest solution and doesn't require an additional JavaScript library.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lazy Loading in React
&lt;/h2&gt;

&lt;p&gt;You can use the same approach directly in React:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ProductImage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt;
      &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/images/product.jpg"&lt;/span&gt;
      &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Product"&lt;/span&gt;
      &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"lazy"&lt;/span&gt;
      &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"800"&lt;/span&gt;
      &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"600"&lt;/span&gt;
    &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Adding &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; also helps the browser reserve space for the image and can reduce unexpected layout shifts.&lt;/p&gt;

&lt;p&gt;For responsive image techniques, see &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Guides/Responsive_images" rel="noopener noreferrer"&gt;MDN's Responsive Images Guide&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Above-the-Fold vs Below-the-Fold Images
&lt;/h2&gt;

&lt;p&gt;Not every image should be lazy loaded.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Above-the-fold images&lt;/strong&gt; are visible when the page initially loads.&lt;/p&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hero image&lt;/li&gt;
&lt;li&gt;Main product image&lt;/li&gt;
&lt;li&gt;Important banner&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These images generally shouldn't be unnecessarily lazy loaded because they may be important to the initial page experience.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Below-the-fold images&lt;/strong&gt; are not immediately visible.&lt;/p&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Product grid images&lt;/li&gt;
&lt;li&gt;Blog images further down the page&lt;/li&gt;
&lt;li&gt;Gallery images&lt;/li&gt;
&lt;li&gt;Footer images&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are good candidates for lazy loading.&lt;/p&gt;

&lt;p&gt;A simple rule:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Above the fold
→ Load normally / prioritize

Below the fold
→ Lazy load
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  When Should You NOT Lazy Load?
&lt;/h2&gt;

&lt;p&gt;Avoid lazy loading an image when it is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The main hero image&lt;/li&gt;
&lt;li&gt;The primary LCP image&lt;/li&gt;
&lt;li&gt;Immediately visible to the user&lt;/li&gt;
&lt;li&gt;Critical to understanding the page&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Important hero image&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt;
  &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/hero.jpg"&lt;/span&gt;
  &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"React performance"&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't automatically add &lt;code&gt;loading="lazy"&lt;/code&gt; to every image.&lt;/p&gt;

&lt;p&gt;The goal isn't &lt;strong&gt;"lazy load everything."&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The goal is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Load important images early and delay images that aren't immediately needed.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  A Practical React Example
&lt;/h2&gt;

&lt;p&gt;A product page might use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ProductPage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Important image */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt;
        &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/hero.jpg"&lt;/span&gt;
        &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Product"&lt;/span&gt;
        &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"1200"&lt;/span&gt;
        &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"700"&lt;/span&gt;
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Below-the-fold images */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt;
        &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/product-1.jpg"&lt;/span&gt;
        &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Product 1"&lt;/span&gt;
        &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"lazy"&lt;/span&gt;
        &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"800"&lt;/span&gt;
        &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"600"&lt;/span&gt;
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt;
        &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/product-2.jpg"&lt;/span&gt;
        &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Product 2"&lt;/span&gt;
        &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"lazy"&lt;/span&gt;
        &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"800"&lt;/span&gt;
        &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"600"&lt;/span&gt;
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives the browser a clear strategy:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important image → Load early&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Non-critical image → Lazy load&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Need More Image Features?
&lt;/h2&gt;

&lt;p&gt;For applications that need more than native lazy loading, &lt;strong&gt;&lt;a href="https://labs.concatstring.com/products/react-smart-image" rel="noopener noreferrer"&gt;React Smart Image&lt;/a&gt;&lt;/strong&gt; provides features such as lazy loading, priority loading, blur placeholders, skeleton loading, WebP/AVIF support, retry handling, image zoom, and aspect-ratio support.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;SmartImage&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@concatstring/react-smart-image&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SmartImage&lt;/span&gt;
  &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/images/product.jpg"&lt;/span&gt;
  &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Product"&lt;/span&gt;
  &lt;span class="na"&gt;lazy&lt;/span&gt;
  &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;800&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  React Smart Image
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Website:&lt;/strong&gt; &lt;a href="https://labs.concatstring.com/products/react-smart-image" rel="noopener noreferrer"&gt;React Smart Image&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/concatstring-account/react-smart-image" rel="noopener noreferrer"&gt;View source code&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;npm:&lt;/strong&gt; &lt;a href="https://www.npmjs.com/package/@concatstring/react-smart-image" rel="noopener noreferrer"&gt;Install from npm&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live Demo:&lt;/strong&gt; &lt;a href="https://react-smart-image.netlify.app/" rel="noopener noreferrer"&gt;Try the demo&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final Takeaway
&lt;/h2&gt;

&lt;p&gt;Lazy loading is a simple way to avoid loading images that users don't need immediately.&lt;/p&gt;

&lt;p&gt;Remember:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Visible and important → Load early&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Below the fold → Lazy load&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Large images → Optimize&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Modern formats → Consider WebP/AVIF&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Lazy loading works best when it is part of a complete image optimization strategy—not when it is applied to every image blindly.&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>performance</category>
    </item>
    <item>
      <title>React Smart Image: The Free React Image Optimization Library Every Developer Should Try</title>
      <dc:creator>Jaimin Patel</dc:creator>
      <pubDate>Thu, 02 Jul 2026 19:47:51 +0000</pubDate>
      <link>https://dev.to/jaimin_patel/react-smart-image-the-free-react-image-optimization-library-every-developer-should-try-1kng</link>
      <guid>https://dev.to/jaimin_patel/react-smart-image-the-free-react-image-optimization-library-every-developer-should-try-1kng</guid>
      <description>&lt;p&gt;If you've built more than one React app, you've probably written the same image-loading boilerplate more than once.&lt;/p&gt;

&lt;p&gt;A skeleton here. A lazy-loading &lt;code&gt;IntersectionObserver&lt;/code&gt; there. A fallback image when the CDN hiccups. A blur placeholder to avoid layout shift. Retry logic for flaky hosts.&lt;/p&gt;

&lt;p&gt;Every new React project ends up with the same image-loading code—copied from the last project, tweaked a little, and rarely perfect.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sound familiar?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.npmjs.com/package/@concatstring/react-smart-image" rel="noopener noreferrer"&gt;&lt;code&gt;@concatstring/react-smart-image&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt; brings all of those features together in a single component. Simply swap &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; with &lt;code&gt;&amp;lt;SmartImage&amp;gt;&lt;/code&gt; and opt into features like lazy loading, WebP detection, blur placeholders, skeleton loaders, retries, responsive images, and performance metrics—all without changing your existing code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started only takes a minute:
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @concatstring/react-smart-image
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Key Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;✅ Drop-in replacement for &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;✅ Zero runtime dependencies&lt;/li&gt;
&lt;li&gt;✅ Fully typed with TypeScript&lt;/li&gt;
&lt;li&gt;✅ Responsive image support&lt;/li&gt;
&lt;li&gt;✅ Lazy loading&lt;/li&gt;
&lt;li&gt;✅ Skeleton loaders&lt;/li&gt;
&lt;li&gt;✅ Blur placeholders&lt;/li&gt;
&lt;li&gt;✅ Retry with exponential backoff&lt;/li&gt;
&lt;li&gt;✅ Error fallbacks&lt;/li&gt;
&lt;li&gt;✅ Automatic WebP detection&lt;/li&gt;
&lt;li&gt;✅ Image performance metrics&lt;/li&gt;
&lt;li&gt;✅ Works with React 18+&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://react-smart-image.netlify.app/" rel="noopener noreferrer"&gt;🔗 Live Demo&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why We Built React Smart Image
&lt;/h2&gt;

&lt;p&gt;Across multiple React projects, we found ourselves implementing the same image-loading logic repeatedly. Some projects needed lazy loading, while others required blur placeholders, retry logic, responsive images, or skeleton loaders. Maintaining separate implementations for each project quickly became repetitive and difficult to scale.&lt;/p&gt;

&lt;p&gt;We wanted a single component that behaves like a normal &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; while providing modern image optimization features only when needed.&lt;/p&gt;

&lt;p&gt;That's why we built React Smart Image.&lt;/p&gt;

&lt;p&gt;Instead of maintaining multiple utilities across projects, I now use one component everywhere and simply enable the features I need with a few props. The result is cleaner code, a more consistent developer experience, and better image performance out of the box.&lt;/p&gt;

&lt;h2&gt;
  
  
  Drop-in Replacement
&lt;/h2&gt;

&lt;p&gt;Replacing your existing images is as simple as swapping the component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SmartImage&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@concatstring/react-smart-image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SmartImage&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/photo.jpg"&lt;/span&gt; &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"A photo"&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;800&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;className&lt;/code&gt;, &lt;code&gt;style&lt;/code&gt;, &lt;code&gt;onClick&lt;/code&gt;, &lt;code&gt;loading&lt;/code&gt;, &lt;code&gt;ref&lt;/code&gt; — all forwarded to the real &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt;. Nothing new to learn. Enable additional features only when you need them—one prop at a time.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Lazy loading that actually waits for the viewport
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SmartImage&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/hero.jpg"&lt;/span&gt; &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Hero"&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1200&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;lazy&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Images load 100px before they scroll into view — powered by &lt;code&gt;IntersectionObserver&lt;/code&gt;, no scroll listeners, no jank.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Skeleton loaders (with dark-mode support)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SmartImage&lt;/span&gt;
  &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/avatar.jpg"&lt;/span&gt;
  &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"User avatar"&lt;/span&gt;
  &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;skeleton&lt;/span&gt;
  &lt;span class="na"&gt;skeletonColor&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"#1f2937"&lt;/span&gt;
  &lt;span class="na"&gt;skeletonHighlightColor&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"rgba(255,255,255,0.12)"&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An animated shimmer while the image loads — themeable to your brand or dark UI.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Blur placeholders — manual &lt;em&gt;or&lt;/em&gt; automatic
&lt;/h2&gt;

&lt;p&gt;Pass a tiny base64 LQIP the Next.js way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SmartImage&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/landscape.jpg"&lt;/span&gt; &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Landscape"&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1200&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;800&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"blur"&lt;/span&gt; &lt;span class="na"&gt;blurDataURL&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"data:image/jpeg;base64,/9j/4AAQ..."&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or skip the base64 entirely. If your CDN resizes by URL (Cloudinary, imgix, CloudFront…), &lt;code&gt;autoBlur&lt;/code&gt; derives the preview for you:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SmartImage&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/landscape.jpg"&lt;/span&gt; &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Landscape"&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1200&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;800&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"blur"&lt;/span&gt; &lt;span class="na"&gt;autoBlur&lt;/span&gt; &lt;span class="na"&gt;blurWidth&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. Retry with exponential backoff + fallback
&lt;/h2&gt;

&lt;p&gt;CDNs fail. Handle it declaratively instead of with a tangle of &lt;code&gt;onError&lt;/code&gt; handlers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SmartImage&lt;/span&gt;
  &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/flaky-cdn.jpg"&lt;/span&gt;
  &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Product"&lt;/span&gt;
  &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;retry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;retryDelay&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;          &lt;span class="c1"&gt;// 500ms → 1s → 2s&lt;/span&gt;
  &lt;span class="na"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/placeholder.png"&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5. WebP auto-detection
&lt;/h2&gt;

&lt;p&gt;Try the modern format first, fall back automatically if it 404s:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SmartImage&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/photo.jpg"&lt;/span&gt; &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Product"&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;webp&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  6. Responsive images — two strategies
&lt;/h2&gt;

&lt;p&gt;The default &lt;code&gt;srcset&lt;/code&gt; strategy lets the browser pick (DPR-aware). The &lt;code&gt;viewport&lt;/code&gt; strategy always serves the smallest bytes per screen, ignoring device pixel ratio:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SmartImage&lt;/span&gt;
  &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/banner.jpg"&lt;/span&gt;
  &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Banner"&lt;/span&gt;
  &lt;span class="na"&gt;responsive&lt;/span&gt;
  &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt;
  &lt;span class="na"&gt;sizes&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;mobile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;480&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;tablet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;768&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;desktop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1200&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Screen&lt;/th&gt;
&lt;th&gt;
&lt;code&gt;srcset&lt;/code&gt; (default)&lt;/th&gt;
&lt;th&gt;&lt;code&gt;viewport&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Mobile @1×&lt;/td&gt;
&lt;td&gt;480w&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;480w&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mobile @2×&lt;/td&gt;
&lt;td&gt;1200w (DPR-aware)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;480w&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Desktop&lt;/td&gt;
&lt;td&gt;1200w&lt;/td&gt;
&lt;td&gt;1200w&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Host encodes size in the path instead of &lt;code&gt;?w=&lt;/code&gt;? Point it wherever you want with &lt;code&gt;srcSetBuilder&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;srcSetBuilder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{(&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;(\.\w&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;$1`&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
&lt;span class="c1"&gt;// /photo.jpg → /photo-480.jpg&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Compose everything
&lt;/h2&gt;

&lt;p&gt;The features are orthogonal — stack them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SmartImage&lt;/span&gt;
  &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/product.jpg"&lt;/span&gt;
  &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Product photo"&lt;/span&gt;
  &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;lazy&lt;/span&gt;
  &lt;span class="na"&gt;skeleton&lt;/span&gt;
  &lt;span class="na"&gt;webp&lt;/span&gt;
  &lt;span class="na"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/placeholder.png"&lt;/span&gt;
  &lt;span class="na"&gt;retry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;retryDelay&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;onLoadInfo&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;loadTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fromCache&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Loaded in &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;loadTime&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;ms (cache: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;fromCache&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That &lt;code&gt;onLoadInfo&lt;/code&gt; callback hands you &lt;code&gt;loadTime&lt;/code&gt;, &lt;code&gt;naturalWidth/Height&lt;/code&gt;, and a &lt;code&gt;fromCache&lt;/code&gt; flag — real performance telemetry per image, for free.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why not just use &lt;code&gt;next/image&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;next/image&lt;/code&gt; is great — &lt;em&gt;if you're on Next.js&lt;/em&gt;. &lt;code&gt;react-smart-image&lt;/code&gt; works in &lt;strong&gt;any&lt;/strong&gt; React app: Vite, CRA, Remix, Gatsby, a plain SPA. No image server required, no framework lock-in, no runtime dependencies. Think of it as a modern, framework-agnostic upgrade to the standard &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; element.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @concatstring/react-smart-image
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;📦 &lt;a href="https://www.npmjs.com/package/@concatstring/react-smart-image" rel="noopener noreferrer"&gt;npm&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💻 &lt;a href="https://github.com/concatstring-account/react-smart-image" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🔗 &lt;a href="https://react-smart-image.netlify.app/" rel="noopener noreferrer"&gt;Live Demo&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If React Smart Image saves you from writing the same image-loading code again, I'd really appreciate a ⭐ on GitHub.&lt;/p&gt;

&lt;p&gt;Feedback, feature requests, and bug reports are always welcome. If there's a feature you'd like to see, let me know in the comments or open an &lt;a href="https://github.com/concatstring-account/react-smart-image/issues" rel="noopener noreferrer"&gt;issue&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Built by the team at &lt;a href="https://concatstring.com/" rel="noopener noreferrer"&gt;Concatstring&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>performance</category>
    </item>
  </channel>
</rss>
