React device mockups and pure CSS device frames for iPhone, iPad, Android, Pixel, Galaxy, tablets, and app screenshots.
react-device-bezels renders realistic device shells around any React content. Use it for app previews, product pages, documentation, screenshots, portfolios, launch pages, or internal design tools. If you need a React device frameset, iPhone mockup, Android device frame, or screenshot wrapper, this package gives you a lightweight CSS-based option.
Live demo | npm package | GitHub repository
- Pure SCSS/CSS bezels, no device image assets required
- Works with JSX, screenshots, videos, canvases, and any React children
- Safe-area-aware scroll container for Dynamic Island, notches, punch-hole cameras, and landscape cutouts
- iOS and Android phones, tablets, and foldables
- Device color, orientation, zoom, and custom screen dimensions
- Typed React API with ESM, CJS, and TypeScript declarations
- Compiled CSS and source SCSS exports
- Wrap app screenshots in iPhone, iPad, Pixel, and Galaxy frames
- Render live React UI inside realistic device mockups
- Build product landing pages, portfolios, app store previews, docs, and launch pages
- Create responsive mobile previews without image-based device assets
- Show portrait and landscape app states in one React component
- Build screenshot galleries, product mockups, and mobile UI documentation
npm install react-device-bezelsimport { DeviceFrame } from "react-device-bezels";
import "react-device-bezels/styles.css";
export function Preview() {
return (
<DeviceFrame device="iphone-16" color="natural">
<main style={{ display: "grid", gap: 16 }}>
<h1>Dashboard</h1>
<p>This is real JSX rendered inside the device screen.</p>
<button type="button">Create report</button>
</main>
</DeviceFrame>
);
}For full-bleed screenshots, pass an image as the child and make it fill the screen.
import { DeviceFrame } from "react-device-bezels";
import "react-device-bezels/styles.css";
export function ScreenshotPreview() {
return (
<DeviceFrame device="pixel-9-pro" color="black">
<img
src="/screenshot.png"
alt="App screenshot"
style={{
display: "block",
height: "100%",
objectFit: "cover",
width: "100%",
}}
/>
</DeviceFrame>
);
}Children render inside .df-device__content, a safe-area-aware scroll container. Content avoids the notch, island, punch-hole camera, and landscape cutouts automatically. Scrollbars are hidden by default while scrolling remains enabled.
<DeviceFrame device="iphone-16-pro" color="natural">
{({ device, orientation }) => (
<section>
<p>{device.label}</p>
<p>{orientation}</p>
</section>
)}
</DeviceFrame>Use screenClassName or screenStyle for the full screen surface. Use contentClassName or contentStyle for the scrollable inner content.
type DeviceFrameProps = {
device?: DeviceName;
color?: DeviceColor | string;
orientation?: "portrait" | "landscape";
landscape?: boolean;
width?: number | string;
height?: number | string;
zoom?: number;
className?: string;
frameClassName?: string;
screenClassName?: string;
contentClassName?: string;
style?: React.CSSProperties;
screenStyle?: React.CSSProperties;
contentStyle?: React.CSSProperties;
children?: React.ReactNode | ((props: DeviceFrameRenderProps) => React.ReactNode);
};| Prop | Default | Description |
|---|---|---|
device |
"iphone-15" |
Preset device name. |
color |
Device default | Preset color name or any CSS color value. |
orientation |
"portrait" |
"portrait" or "landscape". |
landscape |
false |
Convenience boolean for landscape orientation. |
width |
Preset width | Custom screen width before bezel chrome. |
height |
Preset height | Custom screen height before bezel chrome. |
zoom |
1 |
Scales the rendered device. |
className |
- | Class for the outer wrapper. |
frameClassName |
- | Class for the hardware shell. |
screenClassName |
- | Class for the clipped screen surface. |
contentClassName |
- | Class for the safe, scrollable content layer. |
style |
- | Inline styles and CSS variables for the outer wrapper. |
screenStyle |
- | Inline styles for the screen surface. |
contentStyle |
- | Inline styles for the scrollable content layer. |
children |
- | React content or a render function. |
DeviceName is inferred from DEVICE_PRESETS, so the TypeScript type always matches the exported preset list.
import { DEVICE_PRESETS } from "react-device-bezels";
const devices = DEVICE_PRESETS.map((device) => device.name);The package currently includes 76 presets across these families:
- iPhone 16, 15, 14, 13, 12, 11, X/XR, 8 Plus, and SE
- iPad Pro, iPad Air, iPad, and iPad Mini
- Google Pixel 9, 8, 7, 6, Fold, and Pixel Tablet
- Samsung Galaxy S25, S24, S23, S22, Z Flip, Z Fold, and Galaxy Tab
- OnePlus 13, 12, and Open
- Xiaomi 15, 15 Ultra, and 14
Import compiled CSS:
import "react-device-bezels/styles.css";Or import source SCSS:
@use "react-device-bezels/styles.scss";The outer element exposes CSS variables for advanced customization:
<DeviceFrame
device="galaxy-s25-ultra"
orientation="landscape"
color="#1d2128"
style={{
"--df-bezel": "12px",
"--df-frame-radius": "28px",
} as React.CSSProperties}
/>Portrait iPhone with JSX:
<DeviceFrame device="iphone-16" color="natural" zoom={0.72}>
<YourApp />
</DeviceFrame>Landscape Android preview:
<DeviceFrame device="galaxy-s25-ultra" orientation="landscape" color="black">
<video src="/demo.mp4" autoPlay muted loop />
</DeviceFrame>Custom dimensions:
<DeviceFrame device="iphone-16" width={390} height={844} color="#d8d2c4">
<CanvasPreview />
</DeviceFrame>npm install
npm run dev
npm run checknpm run check typechecks the package, builds ESM/CJS/type declarations, compiles CSS, and runs an npm pack dry-run.
import { DeviceFrame, DEVICE_PRESETS } from "react-device-bezels";
import "react-device-bezels/styles.css";@use "react-device-bezels/styles.scss";- Frames are CSS approximations intended for previews and mockups, not exact CAD/device templates.
- Screen sizes are logical CSS viewport dimensions, not physical hardware pixels.
- Android viewport dimensions can vary by browser, display size, and user scaling settings.
MIT

