beta

Device Mockup — .mv-device

Pure-CSS device frames around any content: iPhone (Dynamic Island, buttons), Android (punch-hole), iPad portrait/landscape, MacBook (notch, aluminum base) and a browser window (traffic lights, address bar via data-url); dark or light bezels, all scaled from a single width.

CategoryMedia
TypeCSS only (.mv-device)
Statusbeta
Keywordsdevice, mockup, iphone, android, ipad, macbook, browser, safari, frame, screen

When to use

Avoid when

Install

node scripts/add.mjs device-mockup --out ./src/marvelous

AI agent with the Marvelous UI MCP server: install_components({ slugs: ["device-mockup"], target_dir: "<absolute path>/src/marvelous", framework: "react" }).

Files copied (dependencies included): tokens/tokens.css, core/base.css, components/device-mockup/device-mockup.css.

Usage

Canonical markup — start from it and customize with attributes, data-* and CSS variables:

<div style="display:grid;gap:3rem;width:100%;justify-items:center">
  <div style="display:flex;flex-wrap:wrap;gap:3rem 3.5rem;align-items:flex-end;justify-content:center">
    <!-- iPhone: audio player -->
    <div class="mv-device" data-device="iphone" style="--mv-device-width:15rem">
      <div class="mv-device-screen" style="display:grid;grid-template-rows:1fr auto;background:linear-gradient(180deg,oklch(0.42 0.16 300),oklch(0.2 0.06 280));color:#fff;font:13px/1.35 var(--mv-font-sans)">
        <div style="display:grid;place-items:center;padding:3.2rem 1.2rem 0">
          <div aria-hidden="true" style="width:100%;aspect-ratio:1;border-radius:14px;background:radial-gradient(circle at 70% 30%,#fde68a 0 14%,transparent 15%),linear-gradient(160deg,transparent 55%,#4c1d95 55.5%),linear-gradient(180deg,#f472b6,#fb923c);box-shadow:0 20px 40px -12px #0008"></div>
        </div>
        <div style="padding:1rem 1.2rem 1.8rem;display:grid;gap:.7rem">
          <div><strong style="display:block;font-size:15px">August Light</strong><span style="opacity:.7">Clear Nights</span></div>
          <div aria-hidden="true" style="height:4px;border-radius:4px;background:linear-gradient(90deg,#fff 38%,#fff4 38%)"></div>
          <div aria-hidden="true" style="display:flex;justify-content:space-between;font-size:11px;opacity:.7"><span>1:24</span><span>-2:11</span></div>
          <div aria-hidden="true" style="display:flex;justify-content:center;gap:1.6rem;align-items:center;font-size:18px"><span>⏮</span><span style="display:grid;place-items:center;width:44px;height:44px;border-radius:50%;background:#fff;color:#1e1b4b;font-size:16px">❚❚</span><span>⏭</span></div>
        </div>
      </div>
    </div>

    <!-- Android: messaging, light bezels -->
    <div class="mv-device" data-device="android" data-tone="light" style="--mv-device-width:14.5rem">
      <div class="mv-device-screen" style="font:12px/1.35 var(--mv-font-sans);padding:2.6rem .9rem 1rem;display:grid;align-content:start;gap:.55rem;background:var(--mv-bg-subtle)">
        <strong style="font-size:18px;letter-spacing:-.02em;padding-inline:.2rem">Messages</strong>
        <div style="display:flex;gap:.6rem;align-items:center;padding:.55rem;border-radius:12px;background:var(--mv-surface)"><span aria-hidden="true" style="flex:none;width:32px;height:32px;border-radius:50%;background:linear-gradient(135deg,#f472b6,#8b5cf6)"></span><span style="min-width:0"><b style="display:block">Olivia Park</b><span style="color:var(--mv-fg-muted)">Meet at 7 p.m.?</span></span></div>
        <div style="display:flex;gap:.6rem;align-items:center;padding:.55rem;border-radius:12px;background:var(--mv-surface)"><span aria-hidden="true" style="flex:none;width:32px;height:32px;border-radius:50%;background:linear-gradient(135deg,#34d399,#0ea5e9)"></span><span style="min-width:0"><b style="display:block">Studio Team</b><span style="color:var(--mv-fg-muted)">Kenji: mockup approved</span></span></div>
        <div style="display:flex;gap:.6rem;align-items:center;padding:.55rem;border-radius:12px;background:var(--mv-surface)"><span aria-hidden="true" style="flex:none;width:32px;height:32px;border-radius:50%;background:linear-gradient(135deg,#fbbf24,#f97316)"></span><span style="min-width:0"><b style="display:block">Mom</b><span style="color:var(--mv-fg-muted)">Got the photo ❤</span></span></div>
        <div style="display:flex;gap:.6rem;align-items:center;padding:.55rem;border-radius:12px;background:var(--mv-surface)"><span aria-hidden="true" style="flex:none;width:32px;height:32px;border-radius:50%;background:linear-gradient(135deg,#60a5fa,#6366f1)"></span><span style="min-width:0"><b style="display:block">Boston Carpool</b><span style="color:var(--mv-fg-muted)">Pickup confirmed for 8:15</span></span></div>
      </div>
    </div>

    <!-- iPad landscape: dashboard -->
    <div class="mv-device" data-device="ipad" data-orientation="landscape" style="--mv-device-width:27rem">
      <div class="mv-device-screen" style="display:grid;grid-template-columns:5.5rem 1fr;font:11px/1.3 var(--mv-font-sans)">
        <nav aria-hidden="true" style="display:grid;align-content:start;gap:.35rem;padding:.9rem .6rem;background:var(--mv-bg-muted);color:var(--mv-fg-muted)"><b style="color:var(--mv-fg);margin-bottom:.3rem">Lumen</b><span style="padding:.3rem .4rem;border-radius:6px;background:var(--mv-accent-subtle);color:var(--mv-accent-fg)">Overview</span><span style="padding:.3rem .4rem">Sales</span><span style="padding:.3rem .4rem">Customers</span><span style="padding:.3rem .4rem">Settings</span></nav>
        <div style="padding:.9rem;display:grid;gap:.6rem;align-content:start">
          <b style="font-size:14px">This month</b>
          <div style="display:grid;grid-template-columns:repeat(3,1fr);gap:.45rem"><span style="padding:.5rem;border-radius:8px;border:1px solid var(--mv-border)">Revenue<b style="display:block;font-size:14px">$48,210</b></span><span style="padding:.5rem;border-radius:8px;border:1px solid var(--mv-border)">Orders<b style="display:block;font-size:14px">1,284</b></span><span style="padding:.5rem;border-radius:8px;border:1px solid var(--mv-border)">Avg. order<b style="display:block;font-size:14px">$37.50</b></span></div>
          <div aria-hidden="true" style="display:flex;align-items:flex-end;gap:5px;height:6.5rem;padding:.6rem;border-radius:8px;border:1px solid var(--mv-border)"><span style="flex:1;height:38%;border-radius:3px;background:var(--mv-accent-subtle)"></span><span style="flex:1;height:52%;border-radius:3px;background:var(--mv-accent-subtle)"></span><span style="flex:1;height:45%;border-radius:3px;background:var(--mv-accent-subtle)"></span><span style="flex:1;height:66%;border-radius:3px;background:var(--mv-accent-subtle)"></span><span style="flex:1;height:58%;border-radius:3px;background:var(--mv-accent-subtle)"></span><span style="flex:1;height:78%;border-radius:3px;background:var(--mv-accent-subtle)"></span><span style="flex:1;height:70%;border-radius:3px;background:var(--mv-accent-subtle)"></span><span style="flex:1;height:92%;border-radius:3px;background:var(--mv-accent)"></span></div>
          <div style="display:flex;justify-content:space-between;color:var(--mv-fg-muted)"><span>Last order · 2 min ago</span><b style="color:var(--mv-success)">+12.4%</b></div>
        </div>
        </div>
      </div>
    </div>
  </div>

  <div style="display:flex;flex-wrap:wrap;gap:3rem;align-items:flex-end;justify-content:center;width:100%">
    <!-- MacBook: landing page -->
    <div class="mv-device" data-device="macbook" style="--mv-device-width:30rem">
      <div class="mv-device-screen" style="display:grid;place-items:center;text-align:center;background:radial-gradient(80% 70% at 50% 0%,var(--mv-accent-subtle),transparent),var(--mv-bg);font:12px/1.4 var(--mv-font-sans);padding:1.2rem">
        <div>
          <span style="display:inline-block;padding:.2rem .6rem;border-radius:999px;border:1px solid var(--mv-border);color:var(--mv-fg-muted);font-size:10px">New · Version 3.0</span>
          <p style="margin:.6rem 0 .3rem;font:700 22px/1.1 var(--mv-font-sans);letter-spacing:-.03em">Design faster,<br>ship better.</p>
          <p style="margin:0 0 .8rem;color:var(--mv-fg-muted)">Production-ready components.</p>
          <span style="display:inline-block;padding:.45rem .9rem;border-radius:8px;background:var(--mv-accent);color:var(--mv-fg-on-accent);font-weight:600">Get started</span>
        </div>
      </div>
    </div>

    <!-- Browser: address bar, follows the theme -->
    <div class="mv-device" data-device="browser" data-url="lumen.studio/pricing" style="--mv-device-width:30rem">
      <div class="mv-device-screen" style="padding:1.2rem;display:grid;gap:.8rem;font:12px/1.4 var(--mv-font-sans)">
        <div style="text-align:center"><b style="font-size:16px;letter-spacing:-.02em">Simple pricing</b><p style="margin:.2rem 0 0;color:var(--mv-fg-muted)">No commitment, cancel anytime.</p></div>
        <div style="display:grid;grid-template-columns:1fr 1fr;gap:.6rem">
          <div style="padding:.8rem;border-radius:10px;border:1px solid var(--mv-border)"><b>Solo</b><p style="margin:.2rem 0;font-size:18px;font-weight:700">$9<small style="font-size:11px;color:var(--mv-fg-muted);font-weight:400"> /mo</small></p><span style="color:var(--mv-fg-muted)">1 project · 5 GB</span></div>
          <div style="padding:.8rem;border-radius:10px;border:1px solid var(--mv-accent);background:var(--mv-accent-subtle)"><b>Studio</b><p style="margin:.2rem 0;font-size:18px;font-weight:700">$29<small style="font-size:11px;color:var(--mv-fg-muted);font-weight:400"> /mo</small></p><span style="color:var(--mv-fg-muted)">Unlimited · 200 GB</span></div>
        </div>
      </div>
    </div>
  </div>
</div>

API

Attributes

NameTypeDefaultDescription
data-deviceiphone | android | ipad | macbook | browserDevice type.
data-tonedark | lightdark (browser: follows the theme)Dark or light bezels; for browser, forces a light or dark toolbar.
data-orientationportrait | landscapeportraitipad: orientation.
data-urlstringbrowser: address bar text (no address bar without the attribute).

CSS classes

NameDescription
mv-deviceFrame; every dimension (bezels, radii, buttons) scales with its width.
mv-device-screenScreen area (direct child): clips its content; img/video/iframe fill the screen.

CSS variables

NameDefaultDescription
--mv-device-width18rem · 30rem (ipad) · 38rem (landscape) · 40rem (macbook) · 100% (browser)Reference width.
--mv-device-ratio9/19.5 · 9/20 · 3/4 · 16/10 · autoScreen aspect ratio.
--mv-device-bezel / --mv-device-frame / --mv-device-buttonColors of the glass, metal frame and buttons (artistic).
--mv-device-screen-bgvar(--mv-bg)Screen background.
--mv-device-shadowvar(--mv-shadow-xl)Drop shadow.
--mv-device-toolbar / --mv-device-url-bgbrowser: toolbar and address field.
--mv-device-close / --mv-device-minimize / --mv-device-zoombrowser: traffic lights.

Accessibility

Purely decorative: the chrome is made of pseudo-elements, and only the screen content is exposed. The address bar (data-url) is generated by CSS and may not be read out: give the content a title or alt text if the URL matters. No animation.