Skip to main content

Overview

The Window component creates draggable, macOS-style windows with a title bar, traffic light controls (close, minimize, maximize), and content area. It uses react-draggable for drag functionality and manages maximization state internally.

Features

  • Draggable: Click and drag from the title bar to reposition
  • Traffic Light Controls: Red (close), yellow (minimize), green (maximize/restore)
  • Maximization: Full-screen mode that fills viewport between MenuBar and Dock
  • Focus Management: Brings window to front on click
  • Minimization Support: Can be hidden via isMinimized prop
  • Bounded Dragging: Prevents windows from being dragged above the MenuBar

Props

title
string
required
Window title displayed in the center of the title bar
children
React.ReactNode
required
Content to render inside the window body
onClose
() => void
required
Callback fired when the red close button is clicked
onMinimize
() => void
required
Callback fired when the yellow minimize button is clicked
onFocus
() => void
required
Callback fired when the window is clicked (used for z-index management)
zIndex
number
required
Z-index value for stacking order (managed by parent Desktop component)
defaultPosition
{ x: number; y: number }
required
Initial position of the window when first rendered
width
number
default:"720"
Width of the window in pixels (ignored when maximized)
height
number
default:"500"
Height of the window in pixels (ignored when maximized)
isMinimized
boolean
default:"false"
Whether the window is currently minimized (hidden)

Interface Definition

interface WindowProps {
  title: string;
  children: React.ReactNode;
  onClose: () => void;
  onMinimize: () => void;
  onFocus: () => void;
  zIndex: number;
  defaultPosition: { x: number; y: number };
  width?: number;
  height?: number;
  isMinimized?: boolean;
}

Usage Examples

import Window from "./components/Window";

function App() {
  return (
    <Window
      title="My Application"
      onClose={() => console.log("closed")}
      onMinimize={() => console.log("minimized")}
      onFocus={() => console.log("focused")}
      zIndex={10}
      defaultPosition={{ x: 100, y: 100 }}
      width={600}
      height={400}
    >
      <div className="p-4">
        <h1>Window Content</h1>
      </div>
    </Window>
  );
}

Window Structure

Title Bar

The title bar contains three sections:
<div className="win-titlebar ...">
  {/* Traffic light buttons */}
  <div className="flex items-center gap-1.5">
    <button onClick={onClose} className="... bg-[#ff5f56]">
      <span></span>
    </button>
    <button onClick={onMinimize} className="... bg-[#ffbd2e]">
      <span></span>
    </button>
    <button onClick={() => setIsMaximized(!isMaximized)} className="... bg-[#27c93f]">
      <span>{isMaximized ? "⤡" : "⤢"}</span>
    </button>
  </div>
  
  {/* Title text */}
  <span className="flex-1 text-center ...">{title}</span>
</div>

Content Area

Scrollable content area:
<div className="flex-1 overflow-auto">
  {children}
</div>

Draggable Behavior

The component wraps content with react-draggable:
import Draggable from "react-draggable";

return (
  <Draggable
    nodeRef={nodeRef}
    handle=".win-titlebar"      // Only titlebar is draggable
    cancel=".win-btn"           // Buttons stop propagation
    defaultPosition={defaultPosition}
    bounds={{ top: 30, left: 0 }} // Prevent dragging above MenuBar
  >
    {windowContent}
  </Draggable>
);

Key Properties

  • handle: .win-titlebar - Only the title bar initiates drag
  • cancel: .win-btn - Buttons don’t trigger drag
  • bounds: Prevents windows from going off-screen
  • nodeRef: Avoids React findDOMNode warnings

Maximization

When maximized, the window fills the available space:
const [isMaximized, setIsMaximized] = useState(false);

const maximizedStyle = {
  zIndex,
  position: "fixed",
  top: 28,                              // Below MenuBar
  left: 0,
  width: "100vw",
  height: "calc(100vh - 28px - 80px)", // Between MenuBar and Dock
};

const normalStyle = {
  zIndex,
  width,
  height,
};
Maximized windows are not wrapped in <Draggable> and lose rounded corners.

Minimization

Minimized windows are hidden but remain in the DOM:
style={{
  visibility: isMinimized ? "hidden" : "visible",
  pointerEvents: isMinimized ? "none" : "auto",
}}
This allows for smooth restoration without losing state.

Traffic Light Controls

MacOS-style colored buttons with hover effects:
<button
  onMouseDown={(e) => e.stopPropagation()}
  onClick={(e) => { e.stopPropagation(); onClose(); }}
  className="w-4 h-4 rounded-full bg-[#ff5f56] hover:brightness-125 ..."
>
  <span className="... opacity-0 group-hover:opacity-100"></span>
</button>

Event Propagation

Buttons call stopPropagation() on both onMouseDown and onClick to prevent triggering the drag handler.

Styling

The window uses a dark theme with glassmorphism:
className="
  flex flex-col 
  bg-[#1e1e1e]/95          /* Semi-transparent dark background */
  backdrop-blur-xl          /* Glass effect */
  border border-white/10    /* Subtle border */
  shadow-2xl shadow-black/70 /* Deep shadow */
  rounded-xl                /* Rounded corners (non-maximized) */
"

Title Bar Styling

className="
  flex items-center gap-2 
  px-4 py-2.5 
  bg-[#2a2a2a]             /* Slightly lighter than body */
  border-b border-white/10 
  cursor-move              /* Indicates draggable */
  select-none              /* Prevent text selection */
"

Focus Management

The onFocus callback is triggered when clicking anywhere on the window:
<div onMouseDown={onFocus}>
  {/* Window content */}
</div>
The parent component (Desktop) typically uses this to update z-index:
const bringToFront = (id: string) => {
  topZRef.current += 1;
  setWindows((ws) => ws.map((w) => 
    w.id === id ? { ...w, zIndex: topZRef.current } : w
  ));
};

Integration with Desktop

The Window component is designed to work with the Desktop component:
<Window
  key={window.id}
  title={window.title}
  onClose={() => closeWindow(window.id)}
  onMinimize={() => minimizeWindow(window.id)}
  onFocus={() => bringToFront(window.id)}
  zIndex={window.zIndex}
  defaultPosition={window.defaultPosition}
  width={window.width}
  height={window.height}
  isMinimized={window.isMinimized}
>
  {getContent(window.id)}
</Window>
See Desktop for complete integration details.
  • Desktop - Parent container managing multiple windows
  • Terminal - Main application rendered in a Window
  • Dock - Launches windows and shows minimized state
  • MenuBar - Top bar that defines window boundaries

Build docs developers (and LLMs) love