0

Desktop Window

Wraps content in static macOS, Windows 11, or Ubuntu window chrome.

Release Notes

Version 0.5.0

Wrap a screenshot, a code sample, or a live component in window chrome. The frame is decoration — it does not drag or resize.

import {
  DesktopWindow,
  DesktopWindowContent,

DesktopWindow makes any content look like it is running inside a desktop application window. It is chrome only: it does not drag, resize, minimise, maximise, or track focus. Use it for screenshots, marketing heroes, product mockups, and docs illustrations.

Installation

bunx --bun shadcn@latest add @ondo-ui/desktop-window

Usage

import {
  DesktopWindow,
  DesktopWindowContent,
  DesktopWindowControls,
  DesktopWindowTitle,
  DesktopWindowTitlebar,
} from "@/components/ui/desktop-window"
<DesktopWindow os="macos">
  <DesktopWindowTitlebar>
    <DesktopWindowControls />
    <DesktopWindowTitle>Finder</DesktopWindowTitle>
  </DesktopWindowTitlebar>
  <DesktopWindowContent>Your content</DesktopWindowContent>
</DesktopWindow>

Switching platforms

os accepts "macos" (the default), "windows", and "ubuntu". It flips CSS, not the DOM — write DesktopWindowControls before DesktopWindowTitle on every platform and the layout rearranges itself.

The demo below maps one array over one piece of markup, so the only thing that varies between the three windows is the os value:

Release Notes

os="macos"

Release Notes

os="windows"

Release Notes

os="ubuntu"

import {
  DesktopWindow,
  DesktopWindowContent,

What each value gives you:

ControlsTitleTitlebar
macosthree 12px circles, leftcentered, 13px semibold28px, hairline below
windowsthree 46×32 buttons, flush top-rightleft, 12px32px, no separator
ubuntuthree 24px gray circles, rightcentered, 14px bold48px, hairline below

The platforms also differ in a way that is easy to mistake for a bug: macOS reveals the ✕ − ⤢ glyphs only while the titlebar is hovered, whereas Windows 11 and Ubuntu always show — □ ✕. That is how each system behaves. Ubuntu's close button is a gray circle like its neighbours — the red close button is a Windows trait, not a universal one.

"ubuntu" renders the Yaru/GNOME headerbar that Ubuntu ships by default. Other Linux desktops — KDE Plasma, Xfce, elementary — draw their windows differently and are not covered by this value.

Color and theming

The chrome is deliberately not themed. Titlebar backgrounds, traffic light colors, corner radii, and the Windows close-button red are fixed to the real platform values, so the frame reads as that operating system in any project you install it into.

Only DesktopWindowContent follows your theme — it uses bg-background. If you want the body to match a surface other than the page background, override it:

<DesktopWindowContent className="bg-muted p-6">Your content</DesktopWindowContent>

Interactive controls

Controls are decorative by default: each renders as an aria-hidden span, so a mockup does not add three no-op stops to the tab order. Pass a handler and that control — and only that control — becomes a real <button> with an aria-label and a focus ring.

Inspector

Press a control, or tab into the window.

"use client"

import * as React from "react"

Toolbars, icons, and sidebars

There is no DesktopWindowToolbar or DesktopWindowSidebar. Anything beyond the core anatomy goes in as children. On macOS the title is absolutely positioned across the full titlebar, so a trailing action needs z-10 to stay above it.

Documents

Toolbars, app icons, and sidebars are not separate parts. Put them in the titlebar as children.

import { IconFolder, IconLayoutSidebar } from "@tabler/icons-react"

import { Button } from "@/components/ui/button"

Sizing

DesktopWindow has no intrinsic width. It fills its container, so set the size from outside with className:

<DesktopWindow className="h-96 w-full max-w-3xl">Your content</DesktopWindow>

API Reference

DesktopWindow

PropTypeDefaultDescription
os"macos" | "windows" | "ubuntu""macos"Which platform's chrome to render. Published to every child through context.

Also accepts every div prop.

DesktopWindowControls

PropTypeDefaultDescription
onClose() => voidPromotes the close control to a labeled button.
onMinimize() => voidPromotes the minimise control to a labeled button.
onMaximize() => voidPromotes the zoom (macOS) or maximise (Windows, Ubuntu) control.

Also accepts every div prop.

DesktopWindowTitlebar, DesktopWindowTitle, DesktopWindowContent

Accept every div prop. DesktopWindowTitle is presentational text, not a heading — the frame is decoration and should not add a heading level to your document outline.