@unpic/react
A framework-agnostic React component that renders a responsive, high-performance <img> tag with zero runtime JavaScript.
Repository Health
Technical Analysis
@unpic/react is the React binding for the unpic-img monorepo, a cross-framework component library for responsive images. It renders a plain <img> tag with correctly computed srcset and sizes attributes, detecting the image’s CDN (Cloudinary, Imgix, Shopify, and many others via the unpic core library) and generating resize URLs on the fly, with no build step and no server-side image processing required.
Because the output is a single native <img> (or <picture>/<source> via the companion Source component), there are no wrapper divs, spacer elements, or extra runtime JavaScript to hydrate — making it easy to style and cheap to render. A dedicated @unpic/react/nextjs entry point adds first-class Next.js support, falling back to the built-in Next.js Image Optimizer for local images while still using the CDN’s own resizing for remote ones.
The package is one of eleven framework adapters (React, Vue, Svelte, Solid, Preact, Angular, Qwik, Lit, WebC, Astro, plus the shared core) published from a single pnpm workspace, all built on the same @unpic/core transform logic and validated against a shared cross-framework test suite.
What You Get
- An
Imagecomponent that renders a single native<img>with computedsrcset,sizes, and layout-awarewidth/height/aspect-ratio handling - A
Sourcecomponent for composing<picture>elements with per-breakpoint sources - A dedicated
@unpic/react/nextjsentry point that supports both CDN-hosted and local (import-based) images, using the Next.js Image Optimizer only when needed - Automatic CDN detection (Cloudinary, Imgix, Shopify, Contentful, and more) via the shared
unpicprovider library, so no per-project configuration is required - Support for
fixed,constrained, andfullWidthimage layouts, plus optional low-res blurred placeholders
Common Use Cases
- Marketing and content sites on a headless CMS - render responsive images straight from the CMS’s asset CDN without a separate image-optimization service
- Next.js apps migrating off
next/image- swap in@unpic/react/nextjsto keep CDN-native resizing while retaining a Next.js-compatible fallback for local assets - Multi-framework design systems - teams using several frontend frameworks across projects can share the same
@unpic/coretransform logic and just swap the framework wrapper - E-commerce product images from Shopify or similar CDNs - get correct
srcset/sizesand blurred placeholders with zero server-side image processing
Under The Hood
Architecture
The react package is a thin wrapper: src/image.tsx and src/source.tsx call transformProps/transformSourceProps from the shared @unpic/core package (which owns all CDN-detection and srcset/sizes calculation in packages/core/src/base.ts), then run the result through a small camelizeProps helper (src/camelize.ts) to convert HTML attribute casing (srcset -> srcSet, fetchpriority -> fetchPriority on newer React) before spreading onto a native <img>/<source> element via React.forwardRef. The Next.js variant (src/nextjs.tsx) adds a layer on top that inspects the src prop for Next’s static-import object shape, infers missing width/height from the imported asset, and switches between the CDN path and the Next.js Image Optimizer path based on getProviderForUrl. Because all framework packages in the monorepo delegate to the same core transform function, changing that one abstraction propagates consistently everywhere; the wrapper layer itself carries almost no independent logic, so it would be unusual for a bug to be React-specific rather than core-specific.
Tech Stack
Built with TypeScript, built via tsup (multi-entry cjs+esm with .d.ts generation for index, base, next, nextjs, and next-legacy sub-exports), and validated with publint and @arethetypeswrong/cli (attw) to catch packaging/export-map mistakes before publish. It depends on @unpic/core (workspace-linked) and declares react, react-dom, and next as peer dependencies with broad version ranges (React 17-19, Next 13-16), keeping the package usable across a wide span of consumer app versions. The monorepo is managed with pnpm workspaces and Changesets for versioning/publishing.
Code Quality
Tests use Vitest with React Testing Library (test/react.test.tsx, test/next.test.tsx), and notably import shared test-helpers and shared imgTestCases/sourceTestCases fixtures from a common test/ directory one level up in the monorepo - the same test cases are run against every framework adapter, which is a strong cross-framework regression guard. Types are strict (no any observed in the reviewed files), naming is consistent camelCase/PascalCase, and CI runs via GitHub Actions (.github/workflows). Error handling is minimal by design here (a dev-only console.warn in the deprecated legacy Next component) rather than throwing, consistent with the project’s own documented style guide.
API Design
The public API is deliberately minimal: import Image, pass CDN-agnostic props (src, layout, width, height, alt), and get a real <img> tag back - no provider config, no wrapper components, no extra hydration. The Next.js variant keeps the same prop shape and only asks callers to change the import path, and the package’s own CLAUDE.md documents a consistent internal style guide (explicit return types, named exports, functional patterns), which shows up directly in how uniform the adapters are across all eleven frameworks in the repo.