Blog Implementation Guides 7 min read

SvelteKit Image Fallback Component Pattern

Build a reusable SvelteKit image fallback component using on:error events and fallback.pics placeholder URLs for broken images and missing CMS media fields.

sveltekit image fallbacksvelte on:errorplaceholder imagesvelte componentimage error handling
SvelteKit Image Fallback Component Pattern

SvelteKit provides a clean way to handle image failures using Svelte's on:error directive on img elements. Combined with a reactive let variable for the src, you can build a drop-in fallback component that handles broken URLs and missing CMS media.

For server-rendered pages, resolve fallback URLs in SvelteKit's load function before the component renders so social crawlers and first-paint users never see broken image slots.

Core pattern

on:error fallback in a Svelte component

Svelte makes image fallback straightforward with the on:error directive. Bind the src attribute to a let variable and update it in the error handler.

Keep the fallback value separate from the reactive src so you can check whether the error handler has already triggered — preventing an infinite loop if the fallback URL itself fails.

Implementation text
<!-- src/lib/components/FallbackImage.svelte -->
<script>
  export let src;
  export let alt;
  export let width = 800;
  export let height = 450;

  const fallback = `https://fallback.pics/api/v1/${width}x${height}?text=Image+Not+Found`;
  let currentSrc = src;

  function handleError() {
    if (currentSrc !== fallback) currentSrc = fallback;
  }
</script>

<img
  src={currentSrc}
  {alt}
  {width}
  {height}
  on:error={handleError}
/>

Load function

Resolve missing images in SvelteKit load functions

SvelteKit's load function runs on the server for the initial request and on the client for subsequent navigation. Resolving fallback URLs here ensures the correct src reaches the template before the component mounts.

This is especially valuable for blog post pages and product detail pages where CMS data may have empty image fields.

Implementation tsx
// src/routes/blog/[slug]/+page.server.ts
export async function load({ params }) {
  const post = await fetchPost(params.slug);
  if (!post) error(404, 'Post not found');

  return {
    post: {
      ...post,
      image: post.image
        ?? `https://fallback.pics/api/v1/1200x630.jpg?text=${encodeURIComponent(post.title)}`,
    },
  };
}

Reusable component

Parameterize the fallback with props

A parameterized FallbackImage component accepts custom fallback dimensions and text for different use cases: blog thumbnails, product images, and user avatars each have different size requirements.

Make the fallback reactive with a $: computed declaration so it updates if width or height props change.

Implementation text
<!-- src/lib/components/FallbackImage.svelte (extended) -->
<script>
  export let src;
  export let alt;
  export let width = 800;
  export let height = 450;
  export let fallbackText = 'Image+Not+Available';

  $: fallback = `https://fallback.pics/api/v1/${width}x${height}?text=${fallbackText}`;
  let currentSrc = src;

  $: currentSrc = src; // reset when prop changes

  function handleError() {
    if (currentSrc !== fallback) currentSrc = fallback;
  }
</script>

<img src={currentSrc} {alt} {width} {height} on:error={handleError} />

Avatar pattern

User avatar fallback with initials

User avatar slots are a common fallback case. When no profile image is set, display initials in a colored circle. The fallback.pics avatar route handles this without any additional component markup.

Implementation text
<!-- src/lib/components/Avatar.svelte -->
<script>
  export let src;
  export let name;
  export let size = 48;

  const initials = name.split(' ').map(n => n[0]).join('').toUpperCase().slice(0, 2);
  const fallback = `https://fallback.pics/api/v1/avatar/${size}?text=${initials}`;
  let currentSrc = src ?? fallback;

  function handleError() {
    if (currentSrc !== fallback) currentSrc = fallback;
  }
</script>

<img
  src={currentSrc}
  alt="{name} avatar"
  width={size}
  height={size}
  on:error={handleError}
  style="border-radius: 50%"
/>

OG image

Set og:image fallbacks in SvelteKit layouts

Use SvelteKit's page meta handling in +page.server.ts to pass og:image data down to the head. Resolve the fallback URL in the load function and use it in a +layout.svelte svelte:head block.

This ensures social crawlers and link preview bots receive a valid og:image on the server-rendered response.

Implementation text
<!-- +layout.svelte -->
<svelte:head>
  {#if data.ogImage}
    <meta property="og:image" content={data.ogImage} />
    <meta property="og:image:width" content="1200" />
    <meta property="og:image:height" content="630" />
  {/if}
</svelte:head>

Performance

Always declare width and height on img elements

Svelte does not add implicit width and height to img elements. An img without explicit dimensions causes layout shift when the image loads or when it is replaced by a fallback.

Pass width and height as props to your FallbackImage component and forward them to the img element. For content where dimensions vary, use aspect-ratio CSS to reserve space.

Key takeaways

What to standardize before shipping

  • Use on:error in Svelte to swap src to a fallback URL when the image fails to load.
  • Guard against infinite error loops by comparing currentSrc to the fallback value before updating.
  • Resolve missing CMS image fields in the load function so fallback URLs are ready before the component mounts.
  • Make FallbackImage a parameterized component with width, height, and fallbackText props for reuse across contexts.
  • Always forward width and height props to the img element to prevent layout shift.

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.

Read the docs