Image Composition

An <img> that reserves its space and fades in. It is deliberately not a Next.js Image: no resizing service, no loader, no framework coupling — that belongs to whichever framework the app already chose.

Usage

Abstract gradient

with a blur placeholder

Abstract gradient

flat background, no blur

A photo that never loads

broken source — the placeholder stays

tsx
<Image  src={photo.url}  alt="Abstract gradient"  aspectRatio={4 / 3}  blurDataUrl={photo.blur}  radius="lg"/>

What it handles

  • The space is reserved through aspectRatio, so nothing below the image jumps when it lands.
  • A cached image still fades in correctly. An image can finish loading before React attaches onLoad, which is the bug that leaves a permanently blank frame; the ref checks complete.
  • A broken source keeps the placeholder rather than collapsing to a broken-image icon.
  • alt is required, and "" is allowed — but decorative has to be said out loud rather than achieved by forgetting the prop.

Do

Generate blurDataUrl at build time, a few hundred bytes at most; it ships inline with the markup.

Don't

Use a full-size image as its own placeholder — the point is the bytes that arrive first.

Props

PropTypeDefaultNotes
src / altstringalt is required; pass "" for decorative images.
aspectRationumberWidth / height, e.g. 16 / 9. Reserves the box.
blurDataUrlstringTiny data URI, blurred and scaled up until the real image loads.
backgroundstringFlat colour behind the image when there is no blur placeholder.
fit'cover' | 'contain''cover'object-fit.
radius'none' | 'sm' | 'md' | 'lg' | 'xl''md'Corner token.
loading'lazy' | 'eager''lazy'Eager for anything above the fold.