MacBook Mockup

STARCK UI's MacBook Mockup is a shadcn-compatible React frame for placing arbitrary landing-page content or screenshots inside a MacBook shell. Pass that content as children; the frame keeps a responsive 1792:1165 aspect ratio and can open an optional fullscreen dialog.

Props and responsive frame

children: ReactNode
Required screen content, rendered inside an overflow-hidden inset behind the frame image.
className?: string
Appended to the outer relative wrapper. The default is an empty string.
expandable?: boolean
Defaults to true. Set it to false to omit the fullscreen trigger and dialog.
frameSrc?: string
Defaults to https://ui.starck.studio/preview/macbook-frame.webp.
label?: string
Defaults to Open fullscreen preview and labels both the trigger and dialog.

The frame wrapper is full width up to max-w-4xl and uses aspect-[1792/1165]. The screen content is clipped to proportional insets, while the decorative frame image fills the wrapper with object-contain.

Fullscreen keyboard and focus behavior

When fullscreen opens, the source portals an aria-modal dialog to document.body, saves the trigger, moves focus to the close button on the next animation frame, and sets body overflow to hidden. Its focus selector is button:not([disabled]), [tabindex]:not([tabindex="-1"]). That covers enabled buttons and elements with an explicit tabindex other than -1, but omits native links, inputs, selects and textareas without an explicit tabindex. Because children accepts any ReactNode, those interactive children can let focus leave the dialog. The key handler closes on Escape. Cleanup restores the previous body overflow and returns focus to the trigger. Clicking the backdrop closes the dialog; clicking the framed content does not.

Updated October 7, 2026. The preview and Usage output use the shared macbookMockupExample values. Generated provenance records the component in SessionWatcher at session-watcher-website/components/MacbookPreview.tsx.

FAQ

What can I place inside the React MacBook mockup?
The required children prop accepts any React node, so the screen can contain an image, screenshot, video, or rendered landing-page interface.
How does the optional fullscreen preview behave?
Fullscreen is enabled by default through the expandable prop. The dialog moves focus to its close button, closes with Escape or a backdrop click, locks body scrolling while open, and restores focus to the trigger when it closes. It does not fully contain Tab focus: its selector covers enabled buttons and elements with an explicit tabindex other than -1, but omits native links, inputs, selects and textareas without an explicit tabindex. Interactive ReactNode children can therefore let focus leave the dialog.
What frame and aspect ratio does MacBook Mockup use?
The default frameSrc is https://ui.starck.studio/preview/macbook-frame.webp. The wrapper uses a responsive 1792:1165 aspect ratio, full available width, and a maximum width of 4xl.

Live workspace

One glance. Then back to work.

4 active72% remainingResets in 1h

Install

Add the source directly to your shadcn project.

pnpm dlx shadcn@latest add @starck/macbook-mockup

Usage

<MacbookMockup frameSrc="https://ui.starck.studio/preview/macbook-frame.webp">
  <div className="relative flex size-full flex-col overflow-hidden bg-gradient-to-br from-blue-50 via-white to-violet-100 p-[7%]">
    <div className="flex items-center gap-2">
      <span className="size-2 rounded-full bg-red-400" />
      <span className="size-2 rounded-full bg-amber-400" />
      <span className="size-2 rounded-full bg-emerald-400" />
    </div>
    <div className="m-auto max-w-md text-center">
      <p className="text-[clamp(8px,1.4vw,14px)] text-zinc-500">Live workspace</p>
      <h2 className="mt-2 text-[clamp(14px,3vw,34px)] leading-tight font-semibold tracking-[-0.04em] text-zinc-950">
        One glance. Then back to work.
      </h2>
      <div className="mt-5 flex justify-center gap-2">
        <span className="rounded-full bg-white/80 px-2.5 py-1 text-[clamp(6px,1vw,11px)] text-zinc-600 shadow-sm">4 active</span>
        <span className="rounded-full bg-white/80 px-2.5 py-1 text-[clamp(6px,1vw,11px)] text-zinc-600 shadow-sm">72% remaining</span>
        <span className="rounded-full bg-white/80 px-2.5 py-1 text-[clamp(6px,1vw,11px)] text-zinc-600 shadow-sm">Resets in 1h</span>
      </div>
    </div>
  </div>
</MacbookMockup>