BrowserMock

Browser window mock for product screenshots: a toolbar with window controls and an address bar, and an optional theme picker.

Usage

svelte
<script lang="ts">
  import { BrowserMock } from "@milandekruijf/ui/svelte";

  const themes = [
    { id: "light", label: "Light" },
    { id: "dark", label: "Dark" },
  ];
  const screens: Record<string, string> = {
    light: "/shots/acme-light.webp",
    dark: "/shots/acme-dark.webp",
  };
  let theme = $state("light");
</script>

<BrowserMock
  address="acme.com"
  href="https://acme.com"
  src={screens[theme]}
  alt="Acme homepage"
  {themes}
  onThemeChange={(id) => (theme = id)}
/>

Examples

Product screenshot
The Dennis Costa Care homepage in a desktop browser window
<script lang="ts">
  import { BrowserMock } from "@milandekruijf/ui/svelte";
</script>

<BrowserMock
  address="denniscostacare.com/nl"
  href="https://denniscostacare.com/nl/"
  src="/projects/dennis-costa-care/home-desktop.webp"
  alt="The Dennis Costa Care homepage in a desktop browser window"
/>

Props

PropTypeDefaultDescription
address?string—
Address bar text, rendered as a read-only field with a copy button. Omit to hide the field.
addressLabel?string"Address"
Accessible name for the read-only address field.
copyAriaLabel?string"Copy URL"
Copy button's accessible name while idle.
copiedAriaLabel?string"Copied"
Copy button's accessible name after copying.
href?string—
Live page opened in a new tab by the external button next to the copy button. Omit to hide it.
externalAriaLabel?string"Open in new tab"
External button's accessible name.
src?string—
Screenshot shown in the window.
alt?string""
Alt text for the screenshot.
themes?{ id: string; label: string }[]—
Theme variants; two or more render picker chips below the window.
theme?string | nullnull
Active theme id.
onThemeChange?(id: string) => void—
Called with the new id when a picker chip is pressed.
themePickerLabel?string—
Accessible name for the theme picker group.
aspect?string"16 / 10"
Window aspect ratio; `"auto"` follows the screenshot.
objectPosition?"top" | "center" | "bottom""top"
Crop anchor when the screenshot is taller than the window.
loading?"lazy" | "eager""lazy"
Native image loading; use `"eager"` above the fold.
class?string—
Extra classes merged after the base classes.
children?Snippet—
Custom window content instead of `src`.

Borderless and flat, sharing the code block's surface: a slate.3 toolbar with macOS dots, history/reload icons, and full-height address field (slate.2, squared, no border) whose copy and external buttons supply their own padding. The window crops to `aspect` and anchors a taller screenshot at `objectPosition`, so full-page captures read like a real browser viewport.