Fetching latest headlinesโ€ฆ
React Smart Image: The Free React Image Optimization Library Every Developer Should Try
NORTH AMERICA
๐Ÿ‡บ๐Ÿ‡ธ United Statesโ€ขJuly 2, 2026

React Smart Image: The Free React Image Optimization Library Every Developer Should Try

1 views0 likes0 comments
Originally published byDev.to

If you've built more than one React app, you've probably written the same image-loading boilerplate more than once.

A skeleton here. A lazy-loading IntersectionObserver there. A fallback image when the CDN hiccups. A blur placeholder to avoid layout shift. Retry logic for flaky hosts.

Every new React project ends up with the same image-loading codeโ€”copied from the last project, tweaked a little, and rarely perfect.

Sound familiar?

@concatstring/react-smart-image brings all of those features together in a single component. Simply swap <img> with <SmartImage> 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.

Getting started only takes a minute:

npm install @concatstring/react-smart-image

Key Features

  • โœ… Drop-in replacement for <img>
  • โœ… Zero runtime dependencies
  • โœ… Fully typed with TypeScript
  • โœ… Responsive image support
  • โœ… Lazy loading
  • โœ… Skeleton loaders
  • โœ… Blur placeholders
  • โœ… Retry with exponential backoff
  • โœ… Error fallbacks
  • โœ… Automatic WebP detection
  • โœ… Image performance metrics
  • โœ… Works with React 18+

๐Ÿ”— Live Demo

Why We Built React Smart Image

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.

We wanted a single component that behaves like a normal <img> while providing modern image optimization features only when needed.

That's why we built React Smart Image.

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.

Drop-in Replacement

Replacing your existing images is as simple as swapping the component:

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

<SmartImage src="/photo.jpg" alt="A photo" width={800} height={600} />

className, style, onClick, loading, ref โ€” all forwarded to the real <img>. Nothing new to learn. Enable additional features only when you need themโ€”one prop at a time.

1. Lazy loading that actually waits for the viewport

<SmartImage src="/hero.jpg" alt="Hero" width={1200} height={600} lazy />

Images load 100px before they scroll into view โ€” powered by IntersectionObserver, no scroll listeners, no jank.

2. Skeleton loaders (with dark-mode support)

<SmartImage
  src="/avatar.jpg"
  alt="User avatar"
  width={80}
  height={80}
  skeleton
  skeletonColor="#1f2937"
  skeletonHighlightColor="rgba(255,255,255,0.12)"
/>

An animated shimmer while the image loads โ€” themeable to your brand or dark UI.

3. Blur placeholders โ€” manual or automatic

Pass a tiny base64 LQIP the Next.js way:

<SmartImage src="/landscape.jpg" alt="Landscape" width={1200} height={800}
  placeholder="blur" blurDataURL="data:image/jpeg;base64,/9j/4AAQ..." />

Or skip the base64 entirely. If your CDN resizes by URL (Cloudinary, imgix, CloudFrontโ€ฆ), autoBlur derives the preview for you:

<SmartImage src="/landscape.jpg" alt="Landscape" width={1200} height={800}
  placeholder="blur" autoBlur blurWidth={24} />

4. Retry with exponential backoff + fallback

CDNs fail. Handle it declaratively instead of with a tangle of onError handlers:

<SmartImage
  src="/flaky-cdn.jpg"
  alt="Product"
  width={400}
  height={300}
  retry={3}
  retryDelay={500}          // 500ms โ†’ 1s โ†’ 2s
  fallback="/placeholder.png"
/>

5. WebP auto-detection

Try the modern format first, fall back automatically if it 404s:

<SmartImage src="/photo.jpg" alt="Product" width={600} height={400} webp />

6. Responsive images โ€” two strategies

The default srcset strategy lets the browser pick (DPR-aware). The viewport strategy always serves the smallest bytes per screen, ignoring device pixel ratio:

<SmartImage
  src="/banner.jpg"
  alt="Banner"
  responsive
  strategy="viewport"
  sizes={{ mobile: 480, tablet: 768, desktop: 1200 }}
/>
Screen srcset (default) viewport
Mobile @1ร— 480w 480w
Mobile @2ร— 1200w (DPR-aware) 480w
Desktop 1200w 1200w

Host encodes size in the path instead of ?w=? Point it wherever you want with srcSetBuilder:

srcSetBuilder={(src, width) => src.replace(/(\.\w+)$/, `-${width}$1`)}
// /photo.jpg โ†’ /photo-480.jpg

Compose everything

The features are orthogonal โ€” stack them:

<SmartImage
  src="/product.jpg"
  alt="Product photo"
  width={600}
  height={600}
  lazy
  skeleton
  webp
  fallback="/placeholder.png"
  retry={2}
  retryDelay={1000}
  onLoadInfo={({ loadTime, fromCache }) =>
    console.log(`Loaded in ${loadTime}ms (cache: ${fromCache})`)
  }
/>

That onLoadInfo callback hands you loadTime, naturalWidth/Height, and a fromCache flag โ€” real performance telemetry per image, for free.

Why not just use next/image?

next/image is great โ€” if you're on Next.js. react-smart-image works in any 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 <img> element.

Try it

npm install @concatstring/react-smart-image

If React Smart Image saves you from writing the same image-loading code again, I'd really appreciate a โญ on GitHub.

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 issue.

Built by the team at Concatstring.

Comments (0)

Sign in to join the discussion

Be the first to comment!