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.enPlayground
Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.
<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.jsonOr, 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
| Prop | Type | Default | Description |
|---|---|---|---|
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 |
url | string | "webberui.com" | Text in the Safari address bar (not shown on phones) |
tilt | number | 12 | Maximum 3D tilt angle on hover (deg); set 0 to turn it off |
float | boolean | false | Float continuously up and down |
reveal | boolean | true | Fade in and float up the first time it enters the viewport |
children | ReactNode | — | The screen content |
container | RefObject<HTMLElement> | — | Ref of the nested scroll container; omit to use the window as the scroll container |
className | string | — | Applied to the outermost container (controls the width); in studio mode, to the stage root |
screenClassName | string | — | 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