webdevpuneet.com

Phone Mockup — Free CSS iPhone Device Frame Snippet

Phone Mockup · Layouts · Plain HTML, CSS & JS · Live preview

CategoryLayouts

Copy & paste

Source Code

<div class="pm-stage">
  <div class="pm-phone" id="pmPhone">
    <span class="pm-island"></span>
    <span class="pm-btn pm-vol-up"></span>
    <span class="pm-btn pm-vol-dn"></span>
    <span class="pm-btn pm-power"></span>
    <div class="pm-screen">
      <div class="pm-status">
        <span id="pmTime">9:41</span>
        <span class="pm-status-r">
          <svg viewBox="0 0 18 12" width="17"><rect x="0" y="7" width="3" height="5" rx="1"/><rect x="4" y="5" width="3" height="7" rx="1"/><rect x="8" y="3" width="3" height="9" rx="1"/><rect x="12" y="1" width="3" height="11" rx="1" opacity=".35"/></svg>
          <svg viewBox="0 0 16 12" width="15"><path d="M8 11.5 1 4.5a10 10 0 0 1 14 0z" fill="none" stroke="currentColor" stroke-width="1.4"/><circle cx="8" cy="9.4" r="1.3"/></svg>
          <span class="pm-batt"><i></i></span>
        </span>
      </div>
      <div class="pm-app">
        <header class="pm-head">
          <div><small>Good morning</small><h2>Alex</h2></div>
          <div class="pm-ava">A</div>
        </header>
        <div class="pm-balance">
          <small>Total balance</small>
          <strong>$12,480.55</strong>
          <span class="pm-up">+2.4% this week</span>
        </div>
        <div class="pm-actions">
          <button>Send</button><button>Request</button><button>Top up</button>
        </div>
        <div class="pm-list">
          <div class="pm-tx"><span class="pm-ic" style="background:#6366f1">N</span><div><b>Netflix</b><small>Subscription</small></div><em>-$15.99</em></div>
          <div class="pm-tx"><span class="pm-ic" style="background:#22c55e">S</span><div><b>Salary</b><small>Acme Inc</small></div><em class="pos">+$4,200</em></div>
          <div class="pm-tx"><span class="pm-ic" style="background:#f59e0b">U</span><div><b>Uber</b><small>Transport</small></div><em>-$8.40</em></div>
          <div class="pm-tx"><span class="pm-ic" style="background:#ec4899">D</span><div><b>Dribbble</b><small>Pro plan</small></div><em>-$60.00</em></div>
        </div>
      </div>
    </div>
  </div>
  <button type="button" class="pm-toggle" id="pmToggle">Toggle dark screen</button>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Pure-CSS frame
No phone image — crisp at any size and theme-able.
Nested-radius bezel
Inner and outer radii create a realistic rim.
Dynamic island
A single positioned pill floats over the screen.
Hardware buttons
Volume and power slivers on the frame edges.
Live, scrollable screen
Real DOM content, not a static picture.
CSS status bar
SVG signal, wifi, and a battery with a fill.
Dark-mode toggle
Swap the screen theme with one class.
No dependency
Pure HTML/CSS/JS for mockups and showcases.

About this UI Snippet

Phone Mockup — Pure-CSS Device Frame for App Screens

Screenshot of the Phone Mockup snippet rendered live

A phone mockup is a device frame you drop a screen design into — for landing pages, app-store shots, portfolio pieces, and design presentations. This one is built entirely in HTML and CSS (no image of a phone), so it's crisp at any size, theme-able, and you can put live, scrolling, interactive content inside it. It ships with a sample finance app screen and a live status-bar clock, in vanilla JavaScript with no dependency.

The frame from nested rounded rectangles

The body is a dark rounded box with heavy padding, and the screen is an inner rounded box — the gap between their border-radius values creates the realistic bezel curve where a smaller radius nested inside a larger one reads as a uniform-width rim. An inset box-shadow adds a subtle metal edge, and a large soft drop shadow lifts the whole device off the page. No device photo is involved, so it scales losslessly.

Dynamic island and hardware buttons

The notch is a single absolutely-positioned pill (.pm-island) centered at the top with a high z-index so it floats over the screen content. The volume and power buttons are thin absolutely-positioned slivers hanging off the frame's left and right edges — tiny details that sell the realism for the cost of three empty spans.

A real, scrollable screen — not a picture

Because the screen is live DOM, the app inside it actually works: overflow-y:auto makes the transaction list scroll within the device, the status bar shows a CSS-drawn battery and signal bars, and a toggle switches the screen to dark mode by swapping one class. This is the advantage of a CSS mockup over an image — you can demo genuine interaction, dark mode, and responsive content in context.

The CSS-drawn status bar

The signal bars are four <rect>s of increasing height in a tiny inline SVG, the wifi glyph is a stroked arc, and the battery is a bordered box with a nub pseudo-element (::after) and a percentage fill — all currentColor, so they invert automatically in dark mode. A live clock updates the time so it never looks frozen.

Reusing it as a wrapper

Replace the .pm-app contents with your own screen and the frame becomes a reusable container for any mobile UI. Keep the device markup as a component and pass children into the screen slot — ideal for showcasing a mobile login screen or onboarding flow on a marketing page.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSA CSS phone renders with a sample app screen inside it.
  2. 2
    Scroll the screenThe transaction list scrolls inside the device frame.
  3. 3
    Watch the clockThe status-bar time updates live like a real phone.
  4. 4
    Toggle dark modeOne class swaps the screen between light and dark.
  5. 5
    Drop in your screenReplace the app contents with your own mobile UI.
  6. 6
    Reuse as a wrapperKeep the frame as a component with a screen slot.

Real-world uses

Common Use Cases

App landing pages
Showcase an app screen beside a product hero, with a dynamic island pill and hardware buttons drawn entirely in CSS.
Mobile case study frames
Frame mobile work next to a bento grid, with nested border radii on the bezel creating a realistic rim at any size.
Design presentations
Present a mobile login screen in context, with a live status bar and scrollable app screen inside the frame.
Feature showcases
Pair with a tablet mockup for responsive demonstrations, and swap content freely since no phone image is involved.
Store-style marketing shots
Wrap a music player screen for app-store style marketing, and learn nested-radius bezels as a CSS device art reference.
Related: CSS text-wrap: balance Demo
See the CSS text-wrap: balance Demo for a related layouts pattern worth pairing with this one.

Got questions?

Frequently Asked Questions

Pure CSS. The device is a dark rounded box with padding, the screen is a nested rounded box, and the gap between their border-radius values forms the bezel. The notch and side buttons are positioned spans. Because there's no photo, it stays sharp at any zoom and you can recolor or resize it freely.

Yes — that's the main advantage over a screenshot. The screen is live DOM, so content scrolls with overflow-y:auto, the status-bar clock ticks, and a class toggle switches the screen to dark mode. You can embed forms, lists, animations, or any other snippet and it behaves normally within the frame.

By nesting two rounded rectangles. The outer frame has a large border-radius and padding; the inner screen has a slightly smaller radius. The constant-width gap between them, plus an inset box-shadow for a metal edge, reads as a uniform bezel — a standard trick for CSS device frames that avoids any images.

Replace everything inside the .pm-app element with your markup. The frame, status bar, and scrolling are independent of the content, so your screen just needs to fit the screen width. Keeping the device portion as a reusable component lets you pass different screens in as children.

Make the device frame a component that renders a screen slot (children, a slot, or ng-content) so you can wrap any screen. Move the live-clock interval into a mount effect with cleanup. Toggle dark mode via a state-bound class. In Tailwind, build the frame with rounded-[46px], padding, and shadow utilities, and the status-bar icons with small inline SVGs.