DEV Community

Ondrej Machala
Ondrej Machala

Posted on

Keeping Your VitePress Screenshots From Going Stale

You know that moment. You're proud of your docs - clean VitePress site, nice code examples, helpful screenshots showing exactly how your app works.

Six months later someone opens an issue: "The screenshot on the getting started page doesn't match the actual UI."

You check. They're right. The button moved. The modal got redesigned. Half your screenshots are lying.

The Problem With Manual Screenshots

Here's what updating screenshots manually looks like:

  1. Open browser, navigate to the page
  2. Log in (dig up those test credentials)
  3. Find the exact element
  4. Take screenshot, crop it
  5. Save with the right filename in the right folder
  6. Rebuild docs, check it looks right
  7. Commit, push

Multiply by 20 screenshots. Do this every release.

Nobody does this. The screenshots rot.

The Fix: Define Once, Regenerate Forever

What if you could run one command and every screenshot in your VitePress site updates automatically?

npx heroshot
Enter fullscreen mode Exit fullscreen mode

That's the goal. Let me show you how to set it up.

Step 1: Install

npm install heroshot
Enter fullscreen mode Exit fullscreen mode

Step 2: Define Your Screenshots

Run the visual picker:

npx heroshot config
Enter fullscreen mode Exit fullscreen mode

This opens an interactive browser. Navigate to the page you want to screenshot. Click the element. Name it "dashboard". Done.

Heroshot creates .heroshot/config.json:

{
  "baseUrl": "http://localhost:3000",
  "outputDirectory": "public/heroshots",
  "screenshots": [
    {
      "name": "dashboard",
      "url": "/app/dashboard",
      "selector": ".dashboard-container"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Repeat for each screenshot. Click, name, next.

Step 3: Add the Vite Plugin

Heroshot has a Vite plugin that auto-loads your screenshot config:

// .vitepress/config.ts
import { defineConfig } from 'vitepress';
import { heroshot } from 'heroshot/plugins/vite';

export default defineConfig({
  vite: {
    plugins: [heroshot()],
  },
});
Enter fullscreen mode Exit fullscreen mode

Step 4: Register the Component

Heroshot provides a <Heroshot> component that handles light/dark mode and responsive variants automatically:

// .vitepress/theme/index.ts
import DefaultTheme from 'vitepress/theme';
import type { Theme } from 'vitepress';
import { Heroshot } from 'heroshot/vitepress';
import 'virtual:heroshot-manifest';

export default {
  extends: DefaultTheme,
  enhanceApp({ app }) {
    app.component('Heroshot', Heroshot);
  },
} satisfies Theme;
Enter fullscreen mode Exit fullscreen mode

The virtual:heroshot-manifest import auto-registers your screenshot config.

Step 5: Use It in Markdown

Now in any markdown file:

<Heroshot name="dashboard" alt="Dashboard overview" />
Enter fullscreen mode Exit fullscreen mode

That's it. The component:

  • Finds the screenshot by name from your config
  • Shows light version in light mode, dark in dark mode
  • Handles responsive variants with srcset
  • Lazy loads for performance

No manual ![](/images/dashboard-light.png){.light-only} gymnastics.

Step 6: Regenerate Anytime

When your UI changes, regenerate all screenshots:

npx heroshot
Enter fullscreen mode Exit fullscreen mode

One command. Every screenshot updates. The <Heroshot> component picks up the new images automatically.

Step 7: Handle Auth

Most apps need login. When you run heroshot config, log in manually in the browser. Heroshot saves your session.

Future runs reuse it - even headless.

Automate It

Once this works locally, automate it in CI. Screenshots update on every push.

See the CI/CD integration docs for GitHub Actions setup.

The Result

Before: Screenshots rot. Manual updates. Light/dark mode headaches.

After: One component, one command. Screenshots that stay honest.


heroshot - point, click, capture.

Top comments (0)