React Integration
Learn how to use OPTIMAGE with React. Create reusable components for optimized responsive images.
Introduction
OPTIMAGE works seamlessly with React. Since OPTIMAGE serves standard image URLs over a CDN, no additional packages are required. Simply use the generated URLs in your components.
No dependencies required! OPTIMAGE provides standard image URLs that work with any React setup - Create React App, Vite, Next.js, Remix, and more.
Basic Usage
The simplest way to use OPTIMAGE in React is with a standard img element:
function Hero() {
return (
<img
src="https://cdn.optimage.com/col_abc123/768/hero-banner.webp"
srcSet={`
https://cdn.optimage.com/col_abc123/320/hero-banner.webp 320w,
https://cdn.optimage.com/col_abc123/768/hero-banner.webp 768w,
https://cdn.optimage.com/col_abc123/1280/hero-banner.webp 1280w
`}
sizes="100vw"
alt="Hero banner"
loading="lazy"
/>
);
}OptimizedImage Component
Create a reusable component to simplify usage across your application:
// components/OptimizedImage.tsx
import { ImgHTMLAttributes } from 'react';
const SIZES = [320, 384, 448, 512, 576, 672, 768, 896, 1024, 1152, 1280];
const CDN_URL = 'https://cdn.optimage.com';
interface OptimizedImageProps extends ImgHTMLAttributes<HTMLImageElement> {
collectionId: string;
slug: string;
alt: string;
sizes?: string;
priority?: boolean;
}
export function OptimizedImage({
collectionId,
slug,
alt,
sizes = '100vw',
priority = false,
className,
...props
}: OptimizedImageProps) {
const srcSet = SIZES
.map(size => `${CDN_URL}/${collectionId}/${size}/${slug}.webp ${size}w`)
.join(', ');
const src = `${CDN_URL}/${collectionId}/768/${slug}.webp`;
return (
<img
src={src}
srcSet={srcSet}
sizes={sizes}
alt={alt}
loading={priority ? 'eager' : 'lazy'}
decoding={priority ? 'sync' : 'async'}
className={className}
{...props}
/>
);
}Usage
import { OptimizedImage } from './components/OptimizedImage';
function ProductCard({ product }) {
return (
<div className="product-card">
<OptimizedImage
collectionId="col_products"
slug={product.imageSlug}
alt={product.name}
sizes="(max-width: 768px) 100vw, 33vw"
className="w-full h-48 object-cover rounded-lg"
/>
<h3>{product.name}</h3>
</div>
);
}useOptimage Hook
For more flexibility, create a custom hook that generates URLs:
// hooks/useOptimage.ts
import { useMemo } from 'react';
const SIZES = [320, 384, 448, 512, 576, 672, 768, 896, 1024, 1152, 1280];
const CDN_URL = 'https://cdn.optimage.com';
export function useOptimage(collectionId: string, slug: string) {
return useMemo(() => {
const getUrl = (size: number) =>
`${CDN_URL}/${collectionId}/${size}/${slug}.webp`;
const srcSet = SIZES
.map(size => `${getUrl(size)} ${size}w`)
.join(', ');
return {
src: getUrl(768),
srcSet,
getUrl,
};
}, [collectionId, slug]);
}Usage
import { useOptimage } from './hooks/useOptimage';
function Avatar({ userId, name }) {
const { src, srcSet, getUrl } = useOptimage('col_avatars', userId);
return (
<div>
{/* Responsive image */}
<img
src={src}
srcSet={srcSet}
sizes="64px"
alt={name}
className="w-16 h-16 rounded-full"
/>
{/* Fixed size thumbnail */}
<img
src={getUrl(320)}
alt={name}
className="w-8 h-8 rounded-full"
/>
</div>
);
}Next.js Integration
If you're using Next.js, you can configure the Image component to work with OPTIMAGE:
next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'cdn.optimage.com',
pathname: '/**',
},
],
},
};
module.exports = nextConfig;Using next/image
import Image from 'next/image';
function Hero() {
return (
<Image
src="https://cdn.optimage.com/col_abc123/1280/hero.webp"
alt="Hero banner"
width={1280}
height={720}
priority
className="w-full h-auto"
/>
);
}Note: When using next/image, Next.js handles optimization on its own. You may prefer using the standard img element with OPTIMAGE's pre-optimized images to avoid double optimization and leverage the full srcset.
TypeScript Types
Define types for your OPTIMAGE integration:
// types/optimage.ts
export type OptimageSize =
| 320 | 384 | 448 | 512 | 576
| 672 | 768 | 896 | 1024 | 1152 | 1280;
export interface OptimageImage {
collectionId: string;
slug: string;
}
export const OPTIMAGE_CONFIG = {
cdnUrl: 'https://cdn.optimage.com',
sizes: [320, 384, 448, 512, 576, 672, 768, 896, 1024, 1152, 1280],
defaultSize: 768,
};Best Practices
- 1.Use appropriate sizes attribute: Match the sizes attribute to your layout to help browsers pick the right image.
- 2.Set priority for above-the-fold images: Use
loading="eager"for hero images and LCP elements. - 3.Add width and height: Prevent layout shift by specifying dimensions or using aspect-ratio CSS.
- 4.Use meaningful alt text: Always provide descriptive alt attributes for accessibility.
Complete Example with Best Practices
function ProductGallery({ products }) {
return (
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
{products.map((product, index) => (
<OptimizedImage
key={product.id}
collectionId="col_products"
slug={product.slug}
alt={`${product.name} - ${product.description}`}
sizes="(max-width: 768px) 100vw, 33vw"
priority={index < 3} // First 3 images load eagerly
className="w-full aspect-square object-cover rounded-lg"
style={{ aspectRatio: '1 / 1' }}
/>
))}
</div>
);
}