<?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>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>
