Skip to content
Sign in
FramesDevice stackMenu

Device stackPro

A phone standing in front of a laptop, the classic product composition, with shadows that hold up in light and dark.

ProA phone in front of a laptop. Move the phone or change the finish: the occlusion shadow follows the phone and stays on the laptop.

Installation

$ pnpm dlx shadcn@latest add @chatcn-pro/device-stack

Usage

tsx
import { DeviceStack } from "@/components/ui/chatcn/pro/device-stack"

<DeviceStack width={860} laptop={<YourApp />} phone={<YourChat />} inert />

The stack is one object scaled from a single width: the laptop and the phone are the real frames, at fixed proportions, with the phone overlapping the laptop's corner and standing a little nearer, so its foot sits lower. Each screen renders at its device's real viewport.

Three shadows separate the two devices: an occlusion shadow from the phone that falls only on the laptop's lid (never on the page), a floor shadow under the phone, and the frames' rim, which lifts the phone off a dark laptop with a light edge in dark mode instead of a heavier shadow. The occlusion is gentle on a light page and deeper on a dark one, where a shadow on a dark screen needs more weight to read.

A screen scaled far below 1x shrinks its controls under the 24 px minimum target. When a frame is a picture (a hero, a gallery card), pass inert: the content stays visible but leaves the tab order and the accessibility tree.

Examples

Finishes and empty screens

ProBlack hardware with dark screens and the phone at the start, and silver with a white phone before content loads.

Props

PropTypeNotes
laptopReactNodeThe laptop screen, at a 1440 px viewport
phoneReactNodeThe phone screen, at a 393 px viewport
side"start" | "end"Where the phone stands. Logical. Default end
widthnumberWidth of the whole stack in px. Capped at the container. Default 880
finishFrameFinishOne finish for both. laptopFinish and phoneFinish override it
shadowbooleanEvery shadow. Default true
laptopPropsPartial<LaptopFrameProps>Passed to the laptop, for example notch or screenClassName
phonePropsPartial<PhoneFrameProps>Passed to the phone, for example statusBar

Keyboard

No keyboard behavior of its own. Screens stay live unless the stack is inert.

Accessibility

  • The hardware is decoration and hidden from assistive technology; the screens are read normally unless the stack is inert.
  • In right to left pages, side="end" puts the phone on the left.

Motion

  • Static. Nothing animates.