Mockup
A picture frame for a screenshot — or, better, for a live composition. Wrap anything in a browser window, a desktop window, a code editor, a phone or a tablet, and it reads as a product shot.
The frame is deliberately thin and neutral: it is made entirely of design tokens, so it restyles with your theme instead of being a hardcoded drawing of someone else's window chrome. The content inside is the point.
Basic Usage
Invoices
12 open · 3 overdue
Frame a live composition, not a picture
The best use is not a PNG. Put real components inside and the shot can never go stale — it restyles with the theme and stays in sync with the library.
Updated just now
Code
The code frame gives a snippet a filename tab. Pair it with
Code Block.
public function index(): View
{
return view('teams.index', [
'teams' => auth()->user()->teams,
]);
}Devices
phone and tablet swap the chrome bar for a device shell.
Today
3 tasks left
Dashboard
Everything at a glance.
Screenshots
When you do frame an image, use Image so it stays CLS-safe and keeps its alt text:
{{-- 1. The frame is decoration; the image carries the meaning --}}
<x-wirekit::mockup url="app.example.com">
<x-wirekit::image
src="/screenshots/dashboard.png"
alt="The dashboard showing 12 open invoices"
:ratio="16/9"
/>
</x-wirekit::mockup>
Sizing
A mockup has no size prop — you control its width the way you would any block:
a max-width (or a Tailwind width class) on the component itself.
{{-- 1. A browser / window / code frame fills its container — cap it for a centered demo --}}
<x-wirekit::mockup url="app.example.com" style="max-width: 40rem; margin-inline: auto;">…</x-wirekit::mockup>
{{-- 2. Tailwind width utilities work just as well --}}
<x-wirekit::mockup variant="code" title="Example.php" class="max-w-2xl mx-auto">…</x-wirekit::mockup>
The phone and tablet device frames ship with default sizes so they read as
a device even around a small snippet: the phone is 15rem wide with a 30rem
minimum height, the tablet 22rem wide with a 28rem minimum height, and the
browser / window / code frames fill their container up to 34rem. Override the
width when you want a different scale:
{{-- 3. A wider phone frame --}}
<x-wirekit::mockup variant="phone" style="width: 18rem;">…</x-wirekit::mockup>
The device proportions are chosen to read as a phone or tablet, not to match any specific model — the tablet, for example, is a little squarer than a real one.
Screenshot chrome, not a viewport
A device frame is decorative — it is not a viewport. The screen is an ordinary
element on the page, so media queries inside it (@media (max-width: 640px), a
container query) resolve against the page width, not the frame. Reach for it to
present a composition or a screenshot; it will not tell you how a layout responds at
a phone width. The frame also grows to fit tall content rather than clipping it,
which is why its height is a minimum, not a fixed device height.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
variant |
string | 'browser' |
browser, window, code, phone, tablet |
url |
string|null | null |
Address shown in the browser frame's bar |
title |
string|null | null |
Title / filename shown in the window and code bars |
scope |
string|null | null |
Scoped personalization name |
Accessibility
- All chrome is decorative and
aria-hidden— the traffic lights, the address bar, the notch. A screen-reader user is never told about fake window buttons they cannot press. - The lights are inert spans, not buttons. Rendering them as buttons would put three dead controls in the tab order of every marketing page.
- The slot content carries every bit of the meaning — so frame real components, or an Image with real alt text.
- The address bar is not a URL a user can act on; do not rely on it to communicate anything the page does not also say in text.
Keyboard Interaction
The frame is presentational and does not respond to keyboard input. Anything you place inside keeps its own keyboard behavior.
Pitfalls
- Do not fake a product you do not have. A frame full of invented UI is the oldest tell of a generated landing page. Frame the real thing.
- Do not put an address bar on a non-browser frame. A
urlon awindoworphoneframe is ignored on purpose — it would be a lie. - Do not treat the lights as controls. They are a genre convention, drawn neutral rather than red/amber/green precisely so they do not read as status.
Design Tokens
| Element | Token |
|---|---|
| Frame surface | --color-wk-bg-elevated |
| Frame border | --color-wk-border, --border-wk-width |
| Frame radius | --radius-wk-lg |
| Frame shadow | --shadow-wk-md |
| Chrome bar | --color-wk-bg-muted |
| Label text | --text-wk-xs, --color-wk-text-muted |
| Device shell | --color-wk-bg-inverse |
| Code filename | --font-wk-mono |
Every value is a token — the frame follows your theme rather than drawing someone else's chrome.