MacBook

A laptop frame with the camera housing cut into the display and the scoop cut into its base.

Loading preview

Installation

npx shadcn@latest add @loomui/macbook

Usage

import { MacBook } from "@/components/ui/macbook"
<MacBook />

On its own it is a blank machine with a grey screen. Fill it with a screenshot, or with live markup:

<MacBook src="/app.png" alt="The editor, open on a project" />
<MacBook width={880}>
  <Editor />
</MacBook>

Anything inside is clipped to the screen's radius and sits under the camera housing.

The parts that name it

Two details do the work. The camera housing is bezel intruding into the display, so it is drawn over the screen rather than around it. Cutting a hole in the frame instead puts a step in the bezel that no real machine has.

The base is a little wider than the lid, with a shallow scoop in its front edge. Without the overhang the lid reads as floating above a bar. With it, the machine is standing on something.

<MacBook notch={false} base={false} />

Turn either off for a plainer shape. Dropping the base also drops it from the height, so the frame stays the shape of the lid alone rather than leaving a gap under it.

One number, and it shrinks

width is a maximum, not a fixed size. The frame fills the space it is given and stops there, so it never pushes a narrow screen sideways.

Everything else is a real device measurement expressed as a share of the machine's width, in container units. The lid, both corner radii, the housing, the base, the scoop. That keeps the lid and the base in step at any size. A scale factor worked out in JavaScript would not, once the frame had to shrink to fit.

The component is not client-side. There is no state and no listener, so it renders on the server and costs nothing on the client.

Props

PropTypeDefaultDescription
widthnumber620Largest width the machine is drawn at.
srcstringnoneScreenshot to fill the screen with.
altstring""Description of the screenshot.
notchbooleantrueDraw the camera housing cut into the display.
basebooleantrueDraw the base the lid stands on.
classNamestringnoneMerged onto the frame.

Any other <div> prop is forwarded. children fills the screen when there is no src.

Accessibility

The lid, the housing and the base are all aria-hidden. They are a picture of a laptop, not content. Give src a real alt describing what is on the screen, or leave it empty when the screenshot is decoration beside copy that already says the same thing.