Skip to content
Sign in
FramesPhone frameMenu

Phone framePro

A current flagship phone mockup with a pill cutout, status bar, home indicator and safe area insets, in portrait and landscape.

ProA chatcn chat on a phone. The header clears the status bar and the composer clears the home indicator through the safe area variables.

Installation

$ pnpm dlx shadcn@latest add @chatcn-pro/phone-frame

Usage

tsx
import { PhoneFrame } from "@/components/ui/chatcn/pro/phone-frame"

<PhoneFrame width={320}>
  <div className="h-full pt-(--chatcn-safe-top) pb-(--chatcn-safe-bottom)">
    <YourChat />
  </div>
</PhoneFrame>

Children render at a real 393 x 852 viewport and scale with the frame, so a chat sits at the density it has on the device and fills the glass at any width. The hardware is generic: no brand shapes or marks.

Every finish is its own material: a metal ramp lit from the top left, thin bands lit the way a studio key light wraps around a frame, a specular top edge, near black cover glass with a faint reflection (light glass on white), a hairline where the screen meets the glass, and buttons and camera lenses shaded as solids. Fine detail (the polished chamfer, antenna breaks) only draws once it is a few px wide, so small frames stay crisp instead of stacking hairlines. It is all gradients, inset shadows and SVG: no images, no glare. On a dark page the device gets a light hairline edge instead of a heavier shadow.

The screen exposes its safe area as --chatcn-safe-top, --chatcn-safe-right, --chatcn-safe-bottom and --chatcn-safe-left, in viewport px, the way env(safe-area-inset-*) reads on the device. Pad with pt-(--chatcn-safe-top) and friends.

Examples

Orientation

Changing orientation turns the phone a quarter turn into its new layout. In landscape the status bar hides, the cutout moves to the side and the safe area follows it.

ProTurn the phone: a quarter turn into landscape, with the cutout and safe area moving to the side.

Finishes and status bar

Silver, black with glare, white and a bare frame. Pass a PhoneStatusBar with your own time, signal, Wi-Fi and battery. Under 20% the battery turns red; charging turns it green with a bolt, so the state never rests on color alone.

ProSilver, black and white, with low battery and charging status bars, and a bare frame.

Props

PropTypeNotes
widthnumberRendered width in px. Everything scales from it. Capped at the container
finish"auto" | "silver" | "graphite" | "black" | "white"Hardware material. auto is silver in light, graphite in dark. light and dark still work as aliases for silver and graphite
shadingbooleanMetal sheen, specular edges, chamfer and glass reflection. false draws flat tones. Default true
shadowbooleanLayered contact shadow, plus a floor shadow under upright devices. Default true
glarebooleanA soft diagonal reflection on the screen glass. Default false
viewportnumberCSS width the content renders at before it scales. Smaller makes the UI larger
screenClassNamestringClass names for the screen, for example dark
orientation"portrait" | "landscape"Default portrait
statusBarboolean | ReactNodeDefault bar, your own PhoneStatusBar, or none
homeIndicatorbooleanDefault true
cutoutbooleanThe pill camera cutout. Default true
buttonsbooleanSide buttons. Default true

PhoneStatusBar

PropTypeNotes
timestringDefault 10:24
signalnumber | nullBars, 0 to 4. null hides it
wifinumber | nullStrength, 0 to 3. null hides it
batterynumber0 to 100
chargingbooleanGreen fill and a bolt
layout"split" | "edges"Around a cutout, or pushed to the ends

Keyboard

The frame adds nothing to the tab order. Everything inside the screen keeps its own keyboard behavior.

Accessibility

  • Hardware, the status bar and the home indicator are aria-hidden. Only your content is read.
  • Pass aria-label or wrap the frame in a figure with a caption when the mockup carries meaning.

Motion

  • Orientation changes rotate the frame a quarter turn over 300 ms with the default ease out, from the old footprint to the new one.
  • Under reduced motion the change is a 150 ms opacity fade with no movement.
  • Frames are static. Nothing animates on hover.
  • Under forced-colors: active, the shell and the screen get a system color outline, so the silhouette survives without fills.