Skip to content
goodtabs UI
BrowseBrowse components

Phone frame

A generic phone bezel drawn in hairlines, around a screenshot or live UI.

npx shadcn@latest add https://ui.goodtabs.co/r/phone-frame.json

With the @goodtabs namespace in components.json: npx shadcn@latest add @goodtabs/phone-frame

Inspiration

The tabs worth keeping open.

A hand-picked library for people who build on the web.

A small mobile screen built from live markup.

Screenshot

A grid of browser tabs in monochrome

An image fills the screen edge to edge.

Pair

Light and dark diagonal lines
Concentric rings

Two frames side by side, the second offset down.

Usage

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

<PhoneFrame width="240px">
  <img src="/app.png" alt="The home screen" className="size-full object-cover" />
</PhoneFrame>

Props

PropTypeDefaultDescription
widthstring"260px"Maximum width of the whole bezel. The screen keeps a 9:19 ratio.

Source

phone-frame/phone-frame.tsx
import * as React from "react";
import { cn } from "@/lib/utils";

type PhoneFrameProps = React.ComponentProps<"div"> & {
  /** Width of the whole bezel, for example "260px". The screen keeps a 9:19 ratio. */
  width?: string;
};

/**
 * A generic phone bezel drawn in hairlines. Not modelled on any real device.
 * Children fill the screen; the screen clips them to its rounded corners.
 */
export function PhoneFrame({ width = "260px", className, style, children, ...props }: PhoneFrameProps) {
  return (
    <div
      className={cn("w-full rounded-[2.25rem] border bg-muted p-2", className)}
      style={{ maxWidth: width, ...style }}
      {...props}
    >
      <div className="relative aspect-[9/19] overflow-hidden rounded-[1.75rem] border bg-background">
        <div
          aria-hidden="true"
          className="absolute top-2 left-1/2 z-10 h-4 w-1/4 -translate-x-1/2 rounded-full border bg-muted"
        />
        <div className="absolute inset-0">{children}</div>
      </div>
    </div>
  );
}

For AI agents

Hand your agent this page, the markdown at /components/phone-frame/prompt.md, or the Copy AI prompt button above.

When to use

  • Showing a mobile screen on a landing page or in docs
  • Beside a browser frame to show the same product on two sizes

When not to use

  • When you need a specific device; this is deliberately generic
  • Scrolling content that must stay inside; the screen clips without scrolling

Agent notes

  • Server component; children fill an absolute inset-0 screen, so images want size-full object-cover
  • The notch is a hairline pill, not a real cutout, and sits above children
  • Colours are theme tokens only, so the frame follows light and dark mode

The maths

  • The screen is 9 : 19, a ratio of 0.474, close to a modern phone's 9 : 19.5.
  • Radii nest: the outer corner is 36 = inner 28 + bezel 8, so the gap stays even around the curve.