@unpic/react

A framework-agnostic React component that renders a responsive, high-performance <img> tag with zero runtime JavaScript.

Library
npm
v1.0.2
2,082stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
61/100Good
Development Activity52
Maintenance48
Community52
Maturity52
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
78/100Good
Architecture82
Code Quality78
Innovation68
Learning Curve85

@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 Image component that renders a single native <img> with computed srcset, sizes, and layout-aware width/height/aspect-ratio handling
  • A Source component for composing <picture> elements with per-breakpoint sources
  • A dedicated @unpic/react/nextjs entry 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 unpic provider library, so no per-project configuration is required
  • Support for fixed, constrained, and fullWidth image 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/nextjs to 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/core transform logic and just swap the framework wrapper
  • E-commerce product images from Shopify or similar CDNs - get correct srcset/sizes and 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.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search