Short answer: Keep the adapter thin. It should translate application props into your canonical image request, render standards-based responsive markup, and apply safe loading defaults. Provider syntax, signing, and normalization belong in a lower-level URL builder.
Framework image components can improve defaults, but they can also become a second proprietary API layered over the provider’s API. A deliberate adapter protects application code from both sides and gives the team one place to test image behavior.
What should the component API express?
Accept a stable asset object, alt text, visual role or preset, responsive slot description, and explicit priority. Optional fields can include crop override, focal point, decorative status, and class names. Avoid accepting a completed provider URL as the normal path because it bypasses policy.
Use role names that match the design system: card, article, hero, or avatar. A role can select an aspect ratio, width ladder, crop mode, and quality tier. The component should still allow a bounded size override where layout genuinely requires it.
Make accessibility hard to skip. Require meaningful alt text for informative images or an explicit decorative flag that produces empty alt text. Do not derive alt text from a file name.
Which layer builds URLs?
The adapter should call a provider-neutral typed URL builder. That builder normalizes widths, versions, transformations, and signatures. The framework layer uses the returned candidates and dimensions to render markup.
This separation matters during migration. A new image provider changes the builder adapter, while component props and content records remain stable. A new framework changes rendering, while transformation policy remains stable.
Next.js documents a loader boundary for its Image component, while other frameworks expose different hooks. Treat those hooks as implementation points, not as the domain model.
What markup should it emit?
For a normal responsive image, emit an <img> with src, width-descriptor srcset, accurate sizes, intrinsic dimensions, and alt text. Use <picture> only when art direction or an explicit format fallback requires sources. The picture art-direction guide covers that decision.
Preserve browser-native behavior rather than replacing it with JavaScript source selection. The browser can choose a candidate early when markup is present in the initial response. Client-only calculation can delay discovery and harm the LCP image.
Render width and height that match the source aspect ratio or chosen crop. Responsive CSS can scale the element, while intrinsic geometry reserves space. Do not use fake dimensions that conflict with the actual derivative.
Which loading defaults are safe?
Default normal below-the-fold images to lazy loading when appropriate, but require an explicit priority prop for the likely LCP image. The priority path should disable lazy loading and may set fetchpriority="high". It should not automatically preload every hero-looking component because only the route knows which element is critical.
Limit priority images in development. A warning when several images on one page request high priority can catch misuse. Also warn when sizes is missing for a fluid layout or when the source width is below the largest candidate.
web.dev’s browser-level image lazy loading guide explains native behavior. Use native capabilities where possible and add framework behavior only when it solves a measured gap.
How should errors and fallbacks work?
Avoid swapping to a fallback only after an endless retry loop. Decide whether a missing asset renders a local placeholder, an application-specific empty state, or nothing. Keep the fallback lightweight and prevent it from becoming another failing transformed URL.
Log asset ID, preset, and normalized request when an image fails, but never include signing secrets. Error callbacks should support telemetry without forcing every caller to implement it.
For user-generated content, consider a moderation or processing state before the final asset becomes available. The adapter can render a known placeholder based on asset status rather than discovering incompleteness through a 404.
What tests make the adapter durable?
Use unit or snapshot tests for semantic output: required alt behavior, srcset candidates, sizes, dimensions, priority attributes, art-direction sources, and fallback state. Test a range of props, not only one golden component.
Add browser tests that inspect currentSrc, rendered width, duplicate requests, lazy-load behavior, and LCP discovery on representative routes. A string snapshot cannot prove that the browser selected the intended candidate.
During a static-image migration, run old and new adapters against the same fixtures and compare geometry and visual results. Keep provider integration tests small and deterministic.
The lasting adapter is intentionally unexciting. It makes correct markup easy, exceptions explicit, and provider details replaceable. That small boundary prevents image policy from leaking into every component in the application.



