Performance-optimized React Image component
Drop-in Image implementation of web.dev best practices with zero configuration. Also a great alternative to next/image for non-Next.js projects that still need the automated image optimization tools that the Next Image component provides.
Documentation · Quick Start · Hooks · Examples · Contributing
@page-speed/img is a React-first, OptixFlow-enabled image component that ships Lighthouse-friendly markup by default. It uses useOptimizedImage from @page-speed/hooks to compute pixel-perfect src, DPR-aware srcset, and sizes on the client. Tree shaking keeps the bundle lean—only the media hook is pulled in.
pnpm add @page-speed/imgPeer deps: react and react-dom (17+). For OptixFlow optimization, supply an API key.
import { Img, setDefaultOptixFlowConfig } from "@page-speed/img";
// Optional: set once at app start
setDefaultOptixFlowConfig({ apiKey: process.env.NEXT_PUBLIC_OPTIX_API_KEY!, compressionLevel: 80 });
export function HeroImage() {
return (
<Img
src="https://images.example.com/hero.jpg"
alt="Hero"
width={1280}
height={720}
// Per-image override (optional)
optixFlowConfig={{ renderedFileType: "jpeg", objectFit: "cover" }}
/>
);
}What you get:
- Pixel-perfect primary
srcsized to the rendered element (Lighthouse “Properly size images” pass). - DPR-aware
srcset(1x/2x) for AVIF/WebP/JPEG. - Lazy loading with IntersectionObserver; set
eagerfor above-the-fold. - Optional OptixFlow compression/format selection with a single prop.
src(string, required): Image URL.alt,title, standard<img>attributes.width,height: Set for CLS prevention; used as hints for sizing. Actual rendered size is measured to generate the pixel-perfect URL.loading,decoding: Defaultslazy/async. Seteagerto force above-the-fold fetch.sizes: Override the auto-generatedsizesfromuseOptimizedImage.intersectionMargin,intersectionThreshold: Tweak lazy-load observer.optixFlowConfig:{ apiKey: string; compressionLevel?: number; renderedFileType?: 'avif' | 'webp' | 'jpeg' | 'png'; objectFit?: 'cover' | 'contain' | 'fill'; }.
- Programmatic:
setDefaultOptixFlowConfig({ apiKey: '...' })once during app init. - Browser global (UMD/inline):
<script>
window.PageSpeedImgDefaults = {
optixFlowConfig: {
apiKey: "YOUR_OPTIX_KEY",
compressionLevel: 80,
objectFit: "cover"
}
};
</script>window.OpensiteImgDefaults and window.PAGE_SPEED_IMG_DEFAULTS are also honored for backward compatibility.
<script src="https://unpkg.com/react@18/umd/react.production.min.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js" crossorigin></script>
<script src="https://cdn.jsdelivr.net/npm/@page-speed/img@0.0.2/dist/browser/page-speed-img.umd.js" crossorigin></script>
<div id="app"></div>
<script>
const root = ReactDOM.createRoot(document.getElementById('app'));
root.render(
React.createElement(PageSpeedImg.Img, {
src: 'https://images.example.com/card.jpg',
alt: 'Card',
width: 800,
height: 600,
optixFlowConfig: { apiKey: 'YOUR_OPTIX_KEY', compressionLevel: 70 }
})
);
</script>- The component is client-only (
"use client"). For SSR apps, render it in client components/entry points. - Safe in non-browser contexts: guards exist for
window/IntersectionObserver.
@page-speed/img only imports useOptimizedImage from @page-speed/hooks, keeping bundles small. Both ESM and CJS builds are emitted; UMD is externalized to React/ReactDOM.
pnpm test- Add storybook examples for common layouts (hero, gallery, card).
PRs welcome. Please run pnpm test before submitting.