Drop-in React component for auto-optimized images & media with lazy loading, WebP conversion, and performance optimization
npm install react-media-optimizerbash
npm install react-media-optimizer
`
$3
`bash
yarn add react-media-optimizer
`
$3
`bash
pnpm add react-media-optimizer
`
📌 Peer Dependencies
$3
`jsx
{
"react": ">=16.8.0",
"react-dom": ">=16.8.0"
}
`
🚀 Quick Start
$3
`jsx
import { OptimizedImage } from 'react-media-optimizer';
function HeroSection() {
return (
src="https://example.com/hero-banner.jpg"
alt="Product showcase"
width={1920}
height={1080}
lazy={true}
webp={true}
quality={85}
placeholderSrc="/blur-placeholder.jpg"
className="rounded-lg shadow-xl"
/>
);
}
`
$3
`jsx
import { useOptimizedImage } from 'react-media-optimizer';
function CustomImageGallery({ images }) {
return images.map((image) => {
const { src, isLoading, error, elementRef } = useOptimizedImage({
src: image.url,
lazy: true,
webp: true,
quality: 90,
});
return (
ref={elementRef}
src={src}
alt={image.title}
loading="lazy"
className={isLoading ? 'opacity-50' : 'opacity-100'}
/>
{isLoading && Loading...}
);
});
}
`
$3
`jsx
import { OptimizedVideo } from 'react-media-optimizer';
function ProductDemo() {
return (
src="https://example.com/demo.mp4"
poster="/video-poster.jpg"
width="100%"
height="auto"
lazy={true}
webm={true}
mp4={true}
controls
autoPlay={false}
muted
playsInline
/>
);
}
`
📖 API Reference
$3
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| src | string | Required | Image source URL |
| alt | string | "" | Accessibility description |
| lazy | boolean | true | Enable lazy loading |
| webp | boolean | true | Convert to WebP when supported |
| quality | number | 85 | Image quality (1-100) |
| placeholderSrc | string | undefined | Loading placeholder image |
| fallbackSrc | string | undefined | Fallback on error |
| showLoadingIndicator | boolean | true | Visual loading state |
$3
`typescript
interface UseOptimizedImageOptions {
src: string;
lazy?: boolean; // default: true
webp?: boolean; // default: true
quality?: number; // default: 85
fallbackSrc?: string;
onLoad?: () => void;
onError?: () => void;
}
// Returns:
const {
src, // Optimized source URL
isLoading, // Loading state
error, // Error object if failed
elementRef, // React ref for lazy loading
} = useOptimizedImage(options);
`
$3
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| src | string | Required | Video source URL (.mp4 or .webm) |
| poster | string | undefined | Video poster image |
| lazy | boolean | true | Lazy load video |
| webm | boolean | true | Prefer WebM format |
| mp4 | boolean | true | Include MP4 fallback |
🛠️ Advanced Features
$3
`jsx
import { compressImage, calculateSizeReduction } from 'react-media-optimizer';
async function handleImageUpload(file) {
try {
const compressedFile = await compressImage(file, {
quality: 0.8, // 80% quality
maxWidth: 1920, // Resize if wider
maxHeight: 1080, // Resize if taller
});
const reduction = calculateSizeReduction(
file.size,
compressedFile.size
);
// Example output: "75.3% smaller"
return compressedFile;
} catch (error) {
console.error('Compression failed:', error);
return file; // Fallback to original
}
}
`
---
$3
`jsx
import { supportsWebP, convertToWebP } from 'react-media-optimizer';
// Detect browser support
const webpSupported = await supportsWebP();
// Convert URLs (requires CDN support)
const imageUrl = 'https://example.com/image.jpg';
const optimizedUrl = webpSupported
? convertToWebP(imageUrl)
: imageUrl;
`
📊 Performance Impact
Before & After Comparison:
| Metric | Standard Images | With React Media Optimizer | Improvement |
|--------|----------------|---------------------------|------------|
| Largest Contentful Paint | 4.2s | 1.1s | ⬇️ 74% faster |
| Total Page Weight | 8.7 MB | 1.9 MB | ⬇️ 78% smaller |
| Time to Interactive | 5.8s | 2.3s | ⬇️ 60% faster |
| SEO Score | 72/100 | 94/100 | ⬆️ 22 points |
Based on average e-commerce site with 50 images
🏗️ Framework Integration
$3
`js
import { OptimizedImage } from 'react-media-optimizer';
export default function HomePage() {
return (
src="/nextjs-optimized.jpg"
alt="Next.js optimized"
width={1200}
height={630}
priority={true} // Load immediately for LCP
/>
);
}
`
$3
`js
import { OptimizedImage } from 'react-media-optimizer';
const IndexPage = () => (
src={data.file.publicURL}
alt="Gatsby site"
width={800}
height={600}
lazy={false} // Critical image
/>
);
export default IndexPage;
`
$3
`tsx
import { OptimizedImage } from 'react-media-optimizer';
export default function Index() {
return (
src="/remix-image.jpg"
alt="Remix app"
width={800}
height={400}
webp={true}
/>
);
}
`
---
⚡ Best Practices
$3
`jsx
// Above-the-fold hero image
src="/hero.jpg"
alt="Hero"
lazy={false} // Load immediately
priority={true}
/>
// Below-the-fold gallery images
src="/gallery-1.jpg"
alt="Gallery item"
lazy={true} // Lazy load
/>
`
$3
`jsx
src="/product.jpg"
alt="Product"
placeholderSrc="/blur-placeholder.jpg"
showLoadingIndicator={true}
/>
`
3. Set Appropriate Quality
`jsx
// High quality for product photos
// Medium quality for thumbnails
// Low quality for background images
`
🐛 Troubleshooting
| Issue | Solution |
|-------|---------|
| Images not lazy loading | Ensure parent container has overflow: auto or overflow: scroll |
| WebP not working | Check if your CDN supports auto-format conversion |
| Compression fails | Verify file is an image and Canvas API is supported |
| TypeScript errors | Update to latest version or check peer dependencies |
$3
`jsx
src="/image.jpg"
alt="Debug"
debug={true} // Logs optimization steps
/>
`
🔄 Migration Guide
$3
`diff
-
+
+ src="/image.jpg"
+ alt="Example"
+ width={800}
+ height={600}
+ />
`
$3
`diff
- import Image from 'next/image';
-
+ import { OptimizedImage } from 'react-media-optimizer';
+
``