Blog Testing 8 min read

Storybook Default Args with Placeholder Image URLs

Set storybook placeholder image URLs as default args for image props so every story renders correctly without requiring real assets or mocked fetch calls.

Storybook placeholder imageDefault argsComponent testingVisual regressionDesign system
Storybook Default Args with Placeholder Image URLs

Storybook stories with image props often show broken-image icons in the default state because no `src` value is provided. Setting a deterministic storybook placeholder image URL as the default arg means every story renders a visually complete component on first open — with correct dimensions and no network dependency on real assets.

This guide covers setting component-level and story-level default args, creating a shared placeholder constants file, integrating with Chromatic for visual regression, and avoiding the common mistake of using random URLs that produce non-deterministic snapshots.

Problem

Why Storybook stories break without image default args

A `ProductCard` component with an `imageSrc` prop renders a broken icon if the story does not provide a value. Designers reviewing the story in Storybook see an incomplete component, and Chromatic's visual regression baseline captures the broken state — meaning any future fix triggers a false positive diff.

Using a real production image URL as the default arg causes a different problem: the URL may change, return a 404, or be unavailable in CI networks. Developers end up committing local image paths that only work on their machine, or skipping the image prop altogether.

A deterministic placeholder URL solves both. The URL is always valid, returns the same SVG for the same parameters, and can be calculated from the component's expected dimensions — making the default arg self-documenting.

Setup

A shared placeholder constants file for all stories

Create a single file that exports placeholder URLs keyed by component or size name. Import from this file in every story that needs image args. When a component's dimensions change, update one constant and all stories update automatically.

Keep the file in `.storybook/` or `src/stories/` depending on your project convention. Avoid putting it in `src/constants/` unless you intend to use the same placeholders in production fallback code — which is actually a valid pattern.

Implementation tsx
// .storybook/placeholders.ts
const BASE = 'https://fallback.pics/api/v1';

export const ph = {
  card:          `${BASE}/320x180/E2E8F0/94A3B8?text=Image`,
  cardLarge:     `${BASE}/640x360/E2E8F0/94A3B8?text=Image`,
  avatar32:      `${BASE}/avatar/32?text=AB`,
  avatar64:      `${BASE}/avatar/64?text=AB`,
  avatar96:      `${BASE}/avatar/96?text=AB`,
  hero:          `${BASE}/1200x400/7C3AED/FFFFFF?text=Hero`,
  thumbnail:     `${BASE}/1200x630?text=Title&style=soft&theme=purple&label=fallback.pics`,
  productSquare: `${BASE}/square/400?text=Product`,
  banner728:     `${BASE}/banner/728x90?text=Banner`,
};

Component story

Setting placeholder default args at the component level

Set image defaults at the component (`Meta`) level so every story in the file inherits them. Override at the story level only when you are specifically testing a different image state — a tall image, a landscape image, a missing image, etc.

For components with multiple image props (e.g. a user card with `avatarSrc` and `coverSrc`), provide defaults for all of them. A partially-rendered component is harder to review than a fully-rendered one.

Implementation tsx
// ProductCard.stories.tsx
import type { Meta, StoryObj } from '@storybook/react';
import { ProductCard } from './ProductCard';
import { ph } from '../../.storybook/placeholders';

const meta: Meta<typeof ProductCard> = {
  component: ProductCard,
  args: {
    imageSrc: ph.card,
    title: 'Running Shoes',
    price: '$89.00',
  },
};
export default meta;

type Story = StoryObj<typeof ProductCard>;

export const Default: Story = {};

export const LargeImage: Story = {
  args: { imageSrc: ph.cardLarge },
};

export const BrokenImage: Story = {
  args: { imageSrc: 'https://example.com/does-not-exist.jpg' },
};

Chromatic

Deterministic placeholders prevent false Chromatic diffs

Chromatic takes a screenshot of each story and compares it to the previous baseline. If the image src is a random URL or a live URL that changes, the screenshot changes every run even if the component code did not change. Chromatic flags this as a diff and requires a manual review decision.

A deterministic placeholder URL returns the exact same SVG pixel-for-pixel on every request. Chromatic's baseline stays clean. Diffs only appear when the component itself changes — which is the correct behavior.

Set `disableSnapshot: false` explicitly on your image-testing stories and `disableSnapshot: true` on stories that are known to have dynamic content (timestamps, random data) to prevent noise from leaking into baseline reviews.

CSF3 pattern

Using the play function to test image error states

CSF3's `play` function lets you write interaction tests inside a story. Test the fallback behavior by starting with a broken src and asserting that the component swaps in the placeholder after the error event fires.

Implementation tsx
export const FallbackOnError: Story = {
  args: { imageSrc: 'https://example.com/broken.jpg' },
  play: async ({ canvasElement }) => {
    const { within, waitFor } = await import('@storybook/testing-library');
    const canvas = within(canvasElement);
    const img = canvas.getByRole('img');

    // simulate load error
    img.dispatchEvent(new Event('error'));

    await waitFor(() => {
      expect(img.getAttribute('src')).toContain('fallback.pics');
    });
  },
};

Related resources

Placeholder infrastructure for testing environments

Placeholder URLs work the same way in Playwright visual regression tests and Cypress end-to-end tests. If your CI environment blocks outbound traffic, the self-hosted Docker container provides the same URL shape locally.

Implementation text
https://fallback.pics/docs/
https://fallback.pics/placeholder-image-api/
https://fallback.pics/blog/figma-handoff-placeholder-urls/
https://fallback.pics/blog/playwright-deterministic-placeholders/

Key takeaways

What to standardize before shipping

  • Set placeholder URLs as component-level default args so every story renders a complete, visually correct component without requiring real assets.
  • Keep all placeholder constants in one file so dimension changes propagate to all stories at once.
  • Deterministic placeholder URLs prevent false Chromatic diffs because the same URL always returns the same SVG.
  • Add a `BrokenImage` story that tests the onerror fallback behavior explicitly alongside the happy-path story.
  • Use the CSF3 `play` function to test that image error events trigger the correct fallback swap in interaction tests.

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