Media

Device Mockup

Safari / iPhone / Android device frames with a 3D hover tilt, floating, and a reveal animation.

Puts any content (a screenshot, live UI) inside a Safari desktop browser frame or an iPhone / Android phone frame, complete with a 3D tilt that follows the cursor and a glass highlight.

Bring this into your project

Run this command in your project folder. The CLI adds the source and dependencies; then follow the usage example below.

npx webberui@latest add device-mockup.en

New project or installation trouble? Start here →

Playground

Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.

12
Active edited usageDefault props
<DeviceMockup/>

The complete example includes the preview layout and data. Install the component first, then paste this file into your project.

Installation

npx webberui@latest add https://webberui.com/r/device-mockup.en.json

Or, once registries are configured in components.json, install it as @webberui/device-mockup.

Usage

import { DeviceMockup } from "@/components/ui/device-mockup";

<DeviceMockup variant="safari" url="webberui.com" className="w-[420px]">
  <img src="/screenshot.png" alt="App" className="h-full w-full object-cover" />
</DeviceMockup>;

Setting variant to "iphone" or "android" switches to a phone frame; the phone frames have a fixed width, while safari takes its width from the outer className (such as w-[420px]).

Studio stage

variant="studio" places the device on a dark studio stage: a radial glow from above, a floor, and a floor reflection; as the page scrolls the device stands up from a 12° tilt-back and scales from 0.92 to 1. The frame on the stage is chosen with studioDevice, and the screen content is still real DOM, so you can drop interactive UI straight in.

<DeviceMockup variant="studio" studioDevice="safari" url="app.webberui.com" className="w-full max-w-2xl">
  <Dashboard />
</DeviceMockup>

In studio mode className is applied to the stage root (controls the stage width); the stage background is always dark and does not follow the light / dark theme.

Inside a nested scroll container

By default the component tracks window scroll. When it sits inside a fixed-height overflow-y-auto container, pass that container's ref to container. Only variant="studio" tracks scroll; the other frames are unaffected.

const scrollerRef = React.useRef<HTMLDivElement>(null);

<div ref={scrollerRef} className="h-[400px] overflow-y-auto">
  <DeviceMockup variant="studio" container={scrollerRef}>{/* content */}</DeviceMockup>
</div>

When the window itself is the scroll container, container can be omitted and behavior is unchanged.

Props

PropTypeDefaultDescription
variant"safari" | "iphone" | "android" | "studio""safari"Device frame style; "studio" is a dark studio stage that stands up as you scroll
studioDevice"safari" | "iphone" | "android""safari"The frame on the stage when variant="studio"; ignored by other variants
urlstring"webberui.com"Text in the Safari address bar (not shown on phones)
tiltnumber12Maximum 3D tilt angle on hover (deg); set 0 to turn it off
floatbooleanfalseFloat continuously up and down
revealbooleantrueFade in and float up the first time it enters the viewport
childrenReactNode—The screen content
containerRefObject<HTMLElement>—Ref of the nested scroll container; omit to use the window as the scroll container
classNamestring—Applied to the outermost container (controls the width); in studio mode, to the stage root
screenClassNamestring—Applied to the screen content frame (background, padding)

Accessibility

  • The studio glow, floor, and reflection are decorative layers marked aria-hidden
  • When the user has "reduce motion" enabled at the system level, the tilt, the floating, and the reveal animation are turned off and it is presented statically; the studio scroll stand-up is disabled too and locked to its end state (0°, scale 1)
  • The tilt is only triggered by a mouse pointer, so touch devices are unaffected
  • The decorative frame elements are all marked aria-hidden, so they do not interfere with announcing the screen content