The Window component (app/components/Window.tsx) provides a macOS-style draggable window with traffic light controls. It uses react-draggable for positioning and supports minimize, maximize, and close operations.
Window Component Props
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 ;
}
Prop Descriptions
Window title displayed in the title bar (center)
Content to render inside the window body
Callback when red close button is clicked
Callback when yellow minimize button is clicked
Callback when window is clicked (brings to front)
CSS z-index value (managed by Desktop component)
defaultPosition
{ x: number; y: number }
required
Initial position on the desktop
Whether the window is minimized (hidden)
Window Controls
The Window component features macOS-style traffic light controls:
< div className = "flex items-center gap-1.5" >
{ /* Close (Red) */ }
< button
onMouseDown = { ( e ) => e . stopPropagation () }
onClick = { ( e ) => { e . stopPropagation (); onClose (); } }
className = "win-btn w-4 h-4 rounded-full bg-[#ff5f56] hover:brightness-125 transition-all group relative"
>
< span className = "absolute inset-0 flex items-center justify-center text-[8px] text-black/70 opacity-0 group-hover:opacity-100 font-bold leading-none" > ✕ </ span >
</ button >
{ /* Minimize (Yellow) */ }
< button
onMouseDown = { ( e ) => e . stopPropagation () }
onClick = { ( e ) => { e . stopPropagation (); onMinimize (); } }
className = "win-btn w-4 h-4 rounded-full bg-[#ffbd2e] hover:brightness-125 transition-all group relative"
>
< span className = "absolute inset-0 flex items-center justify-center text-[8px] text-black/70 opacity-0 group-hover:opacity-100 font-bold leading-none" > − </ span >
</ button >
{ /* Maximize (Green) */ }
< button
onMouseDown = { ( e ) => e . stopPropagation () }
onClick = { ( e ) => { e . stopPropagation (); setIsMaximized (( v ) => ! v ); } }
className = "win-btn w-4 h-4 rounded-full bg-[#27c93f] hover:brightness-125 transition-all group relative"
>
< span className = "absolute inset-0 flex items-center justify-center text-[8px] text-black/70 opacity-0 group-hover:opacity-100 font-bold leading-none" >
{ isMaximized ? "⤡" : "⤢" }
</ span >
</ button >
</ div >
Key implementation details:
Event Propagation Handling
onMouseDown = {(e) => e.stopPropagation()}
onClick = {(e) => { e . stopPropagation (); onClose (); }}
stopPropagation() prevents the click from bubbling to the title bar
Without this, clicking a button would trigger both the button action AND start dragging
Applied to both onMouseDown and onClick for safety
opacity-0 group-hover : opacity-100
Icons (✕, −, ⤢) are hidden by default
Revealed on hover using Tailwind’s group-hover utility
Creates authentic macOS behavior
Custom class used by react-draggable to prevent dragging
Added to cancel=".win-btn" prop in Draggable component
Ensures buttons are clickable, not draggable
Maximize State Management
const [ isMaximized , setIsMaximized ] = useState ( false );
Maximize is the only state managed inside the Window component (not in Desktop):
style = {{
isMaximized
? {
zIndex ,
position: "fixed" ,
top: 28 ,
left: 0 ,
width: "100vw" ,
height: "calc(100vh - 28px - 80px)" , // Exclude MenuBar and Dock
visibility: isMinimized ? "hidden" : "visible" ,
pointerEvents: isMinimized ? "none" : "auto" ,
}
: {
zIndex ,
width ,
height ,
visibility: isMinimized ? "hidden" : "visible" ,
pointerEvents: isMinimized ? "none" : "auto" ,
}
}}
Maximized window behavior:
position: fixed removes it from Draggable control
top: 28 accounts for MenuBar height
Height calculation: 100vh - 28px (MenuBar) - 80px (Dock)
When maximized, window cannot be dragged
React Draggable Integration
< Draggable
nodeRef = { nodeRef as React . RefObject < HTMLElement > }
handle = ".win-titlebar"
cancel = ".win-btn"
defaultPosition = { defaultPosition }
bounds = { { top: 30 , left: 0 } }
>
{ windowContent }
</ Draggable >
Configuration Breakdown
const nodeRef = useRef < HTMLDivElement >( null );
< div ref = { nodeRef } style = {{ zIndex , width , height }} >
{ /* window content */ }
</ div >
Why use nodeRef?
Avoids React findDOMNode deprecation warning
Provides direct reference to draggable element
Required by react-draggable v4+
Only the title bar can initiate dragging: < div className = "win-titlebar shrink-0 flex items-center gap-2 px-4 py-2.5 bg-[#2a2a2a] border-b border-white/10 cursor-move select-none" >
{ /* Traffic lights and title */ }
</ div >
cursor-move indicates draggable area
select-none prevents text selection during drag
Prevents dragging when clicking traffic light buttons: < button className = "win-btn w-4 h-4 rounded-full bg-[#ff5f56]" >
{ /* Close button */ }
</ button >
Without cancel, clicking a button would start dragging the window.
bounds = {{ top : 30 , left : 0 }}
Constraints:
top: 30 prevents dragging above MenuBar
left: 0 prevents dragging off left edge
No right or bottom bounds (windows can move off-screen)
Why allow off-screen dragging?
Matches macOS behavior where windows can be partially dragged off-screen.
Minimize Implementation
visibility : isMinimized ? "hidden" : "visible" ,
pointerEvents : isMinimized ? "none" : "auto" ,
Minimized windows are:
Hidden with visibility: hidden (not display: none)
Non-interactive with pointerEvents: none
Still in the DOM (preserves state)
Can be restored by clicking dock icon
Why not use display: none?
Preserves component state during minimize/restore
Avoids re-mounting and losing scroll position, form inputs, etc.
Maintains react-draggable position state
Window Structure
< div
ref = { nodeRef }
style = { /* dynamic styles */ }
className = "flex flex-col bg-[#1e1e1e]/95 backdrop-blur-xl border border-white/10 shadow-2xl shadow-black/70 overflow-hidden absolute rounded-xl"
onMouseDown = { onFocus }
>
{ /* Title bar */ }
< div className = "win-titlebar shrink-0 flex items-center gap-2 px-4 py-2.5 bg-[#2a2a2a] border-b border-white/10 cursor-move select-none" >
< div className = "flex items-center gap-1.5" >
{ /* Traffic light buttons */ }
</ div >
< span className = "flex-1 text-center text-xs text-gray-400 font-mono truncate px-4" >
{ title }
</ span >
</ div >
{ /* Content */ }
< div className = "flex-1 overflow-auto" >
{ children }
</ div >
</ div >
Layout Classes
Vertical layout: title bar on top, content below bg- [#1 e1e1e ]/95 backdrop-blur-xl
Semi-transparent dark background with blur effect (glassmorphism)
absolute for react-draggable positioning
rounded-xl for macOS-style rounded corners
Prevents title bar from shrinking when window height is small
cursor-move indicates draggable area
select-none prevents accidental text selection during drag
flex-1 takes remaining height after title bar
overflow-auto adds scrollbars when content exceeds window size
Creating Windows
Static Window Example
import Desktop from "./components/Desktop" ;
// In Desktop component's INITIAL_WINDOWS:
{
id : "terminal" ,
title : "[email protected] — terminal" ,
isOpen : true ,
isMinimized : false ,
zIndex : 10 ,
defaultPosition : { x : 140 , y : 50 },
width : 720 ,
height : 500 ,
}
// Rendered by Desktop:
< Window
key = "terminal"
title = "[email protected] — terminal"
onClose = { () => closeWindow ( "terminal" ) }
onMinimize = { () => minimizeWindow ( "terminal" ) }
onFocus = { () => bringToFront ( "terminal" ) }
zIndex = { 10 }
defaultPosition = { { x: 140 , y: 50 } }
width = { 720 }
height = { 500 }
isMinimized = { false }
>
< Terminal embedded />
</ Window >
Dynamic Window Example
// Created by openDoc() in Desktop:
const openDoc = useCallback (( title : string , content : ReactNode ) => {
topZRef . current += 1 ;
const z = topZRef . current ;
const id = `doc- ${ Date . now () } ` ;
const offset = ( topZRef . current % 6 ) * 18 ;
setDynWindows (( ws ) => [ ... ws , {
id ,
title ,
content ,
isMinimized: false ,
zIndex: z ,
defaultPosition: { x: 260 + offset , y: 50 + offset },
}]);
}, []);
// Usage in Finder component:
< TxtFileIcon
name = "arcadiax"
onOpen = { () => openDoc ( "arcadiax.txt" , < ProyectoDoc p = { proyectoData } /> ) }
/>
Positioning Best Practices
Cascading Windows const offset = ( topZRef . current % 6 ) * 18 ;
defaultPosition : { x : 260 + offset , y : 50 + offset }
Dynamic windows cascade diagonally:
Offset increases by 18px for each new window
Resets every 6 windows (modulo operation)
Prevents windows from stacking exactly on top of each other
Safe Zone Coordinates Recommended position ranges:
x: 100–400 (visible on most screens)
y: 40–100 (below MenuBar, good visibility)
Avoid:
y < 30: Overlaps with MenuBar
x < 0 or y < 0: Off-screen on load
Window Size Guidelines Common window sizes:
Terminal: 720×500 (wide for command output)
Finder: 640×400 (balanced for file browsing)
Documents: 480×420 (compact for text)
Photos: 700×480 (landscape photo viewing)
Calendar: 820×520 (large for month view)
Advanced Patterns
Conditional Rendering Based on Maximize State
if ( isMaximized ) {
return windowContent ; // No Draggable wrapper
}
return (
< Draggable { ... props } >
{ windowContent }
</ Draggable >
);
Why?
Maximized windows should not be draggable
Avoids react-draggable trying to position a fixed element
Returns same windowContent JSX in both cases
Focus Management
< div
ref = { nodeRef }
onMouseDown = { onFocus }
{ /* ... */ }
>
Calling onFocus on mouseDown (not onClick):
Triggers immediately when window is clicked
Brings window to front before drag starts
Ensures dragging always moves the topmost window
Accessibility
The current Window implementation lacks keyboard accessibility:
No focus trap inside modals
Traffic light buttons not keyboard accessible
No aria-label on controls
No Escape key to close
Consider adding: < button
aria-label = "Close window"
onKeyDown = { ( e ) => e . key === 'Escape' && onClose () }
{ /* ... */ }
>
Re-render Optimization
Window component is pure (no internal side effects)
Position managed by react-draggable, not React state
Only re-renders when props change
Minimize state changes in parent Desktop component
Visibility vs Display visibility : isMinimized ? "hidden" : "visible"
Benefits of visibility: hidden:
Preserves component state during minimize
Avoids expensive re-mounts
Maintains scroll position and form inputs
Faster restore than unmounting/remounting
See Also