React Image Fallback Patterns: Missing Src, Failed Loads, and Placeholders
Build a React image fallback component that handles missing src values, failed image loads, layout-safe placeholders, and production-safe fallback.pics URLs.
React image fallback work has two separate paths: missing image data before render and failed network loads after render.
A reliable component should handle both paths, preserve layout dimensions, avoid error loops, and use generic fallback URL text that is safe for logs and screenshots.
Search intent
Why React image fallback needs more than onError
Most React snippets solve only one case: an image request fails and onError swaps the src. Real applications also receive empty strings, null media fields, deleted CMS assets, expired CDN URLs, and product records without photos.
Treat missing src and failed loads as separate states. Missing data can use the fallback before React renders the img. Failed loads need an onError handler after the browser tries the source.
Missing src
Use the fallback URL before render when the API, CMS, or product record has no image value.
Failed load
Use onError when the browser receives a URL but the resource fails, times out, or returns unusable image data.
Stable UI
Keep width, height, and aspect ratio consistent so the fallback does not introduce layout shift.
Baseline
Basic React img onError fallback
The shortest React image fallback pattern uses onError to replace the current src. Clear the handler first so a failed fallback image cannot trigger a retry loop.
Use currentTarget instead of target in TypeScript examples. React types currentTarget as the img element that owns the handler.
const fallbackSrc =
"https://fallback.pics/api/v1/600x400?text=Image+Unavailable";
export function ProductImage({ src, alt }: { src: string; alt: string }) {
return (
<img
src={src}
width={600}
height={400}
alt={alt}
onError={(event) => {
event.currentTarget.onerror = null;
event.currentTarget.src = fallbackSrc;
}}
/>
);
} Missing data
Handle missing src before the image renders
If the src prop is undefined, null, or an empty string, the browser may not fire the failure path you expect. Decide on the fallback source before rendering the img.
This is the common path for CMS previews, ecommerce imports, user profiles, and API records where media is optional.
type ProductImageProps = {
src?: string | null;
alt: string;
};
const productFallback =
"https://fallback.pics/api/v1/800x800/F4F4F5/18181B?text=Product+Image";
export function ProductImage({ src, alt }: ProductImageProps) {
const imageSrc = src?.trim() ? src : productFallback;
return (
<img
src={imageSrc}
width={800}
height={800}
alt={alt}
loading="lazy"
decoding="async"
/>
);
} Reusable component
Create a reusable React image fallback component
For production React apps, centralize fallback behavior in one component. That keeps product cards, avatars, article thumbnails, and dashboard previews from each inventing slightly different error handling.
The component below covers missing src values and failed loads while preserving normal img attributes.
import type { ImgHTMLAttributes } from "react";
type FallbackImageProps = Omit<
ImgHTMLAttributes<HTMLImageElement>,
"src" | "alt"
> & {
src?: string | null;
fallbackSrc?: string;
alt: string;
};
const defaultFallback =
"https://fallback.pics/api/v1/600x400?text=Image+Unavailable";
export function FallbackImage({
src,
fallbackSrc = defaultFallback,
alt,
...props
}: FallbackImageProps) {
const resolvedSrc =
typeof src === "string" && src.trim().length > 0 ? src : fallbackSrc;
return (
<img
{...props}
src={resolvedSrc}
alt={alt}
onError={(event) => {
event.currentTarget.onerror = null;
event.currentTarget.src = fallbackSrc;
}}
/>
);
} Use cases
Use different placeholders by image surface
One generic fallback is easy to start with, but repeated UI surfaces usually need different dimensions and labels. A product photo fallback should not look like an avatar fallback.
Use deterministic fallback.pics URLs that match the final surface. That makes the UI easier to scan and keeps screenshot tests stable.
<FallbackImage
src={product.imageUrl}
fallbackSrc="https://fallback.pics/api/v1/800x800?text=Product+Image"
width={800}
height={800}
alt="Product photo"
/>
<FallbackImage
src={user.avatarUrl}
fallbackSrc="https://fallback.pics/api/v1/avatar/96?text=User"
width={96}
height={96}
alt="User avatar"
/>
<FallbackImage
src={article.coverUrl}
fallbackSrc="https://fallback.pics/api/v1/1200x630?text=Article+Image"
width={1200}
height={630}
alt="Article cover"
/> Layout
Prevent layout shift in React image fallbacks
React fallback logic should not change the geometry of the image slot. Keep width and height attributes on the img, and pair them with CSS when the rendered size is responsive.
If the original image slot is square, use a square fallback URL. If it is a social card, use 1200x630. The fallback should preserve the same aspect ratio as the intended image.
<FallbackImage
className="cardImage"
src={item.imageUrl}
fallbackSrc="https://fallback.pics/api/v1/600x400?text=Card+Image"
width={600}
height={400}
alt={item.title}
/>
/* CSS */
.cardImage {
display: block;
width: 100%;
height: auto;
aspect-ratio: 3 / 2;
object-fit: cover;
} State
When to use state instead of mutating currentTarget
Directly setting event.currentTarget.src is fine for a small img wrapper. Use React state when the fallback affects other UI, such as showing a badge, changing copy, or reporting the failed source to a logging function.
Avoid setting state repeatedly on every error. Guard against retry loops by checking whether the current source is already the fallback.
import { useState } from "react";
const fallbackSrc =
"https://fallback.pics/api/v1/600x400?text=Image+Unavailable";
export function TrackedImage({ src, alt }: { src?: string; alt: string }) {
const [imageSrc, setImageSrc] = useState(src || fallbackSrc);
const [usedFallback, setUsedFallback] = useState(!src);
return (
<figure>
<img
src={imageSrc}
width={600}
height={400}
alt={alt}
onError={() => {
if (imageSrc === fallbackSrc) return;
setImageSrc(fallbackSrc);
setUsedFallback(true);
}}
/>
{usedFallback ? <figcaption>Image unavailable</figcaption> : null}
</figure>
);
} Privacy
Keep React fallback URL labels safe
It is tempting to include product names, user names, account identifiers, or request IDs in placeholder text. Do not do that. Image URLs can end up in browser history, CDN logs, analytics tools, error reports, and screenshots.
Use generic labels like Product Image, User, Article Image, Preview, or Image Unavailable. Keep private data in your application state, not in the fallback image URL.
Internal links
Where to go next
Use this article when designing the component pattern. Use the shorter React image fallback guide when you need a quick implementation reference, and the API syntax guide when choosing dimensions, colors, avatars, and text labels.
For Next.js applications, use the Next.js fallback guide instead of assuming every img pattern maps directly to next/image behavior.
React guide: https://fallback.pics/guides/react-image-fallback/
HTML onerror guide: https://fallback.pics/guides/img-onerror-fallback/
Next.js guide: https://fallback.pics/guides/nextjs-image-fallback/
Placeholder image API: https://fallback.pics/placeholder-image-api/
Broken image fallback: https://fallback.pics/broken-image-fallback/
API reference: https://fallback.pics/api/ Key takeaways
What to standardize before shipping
- Handle missing src values before render and failed loads with onError.
- Clear the image error handler or guard state updates to prevent fallback loops.
- Centralize React image fallback behavior in a shared component.
- Match fallback URL dimensions to the final image slot to avoid layout shift.
- Use generic placeholder text and keep private data out of fallback URLs.
Production fallback layer
Use fallback.pics anywhere an image URL is accepted.
Start with one deterministic URL and standardize fallback behavior across your design system.