Building a Modern Window Manager Library for Web Applications
hex

hex @hexcreator

Joined:
Jun 16, 2025

Building a Modern Window Manager Library for Web Applications

Publish Date: Jun 16
0 1

Image description

Table of Contents

  1. Introduction
  2. Design Philosophy and Architecture
  3. Development Process
  4. Core Components Implementation
  5. Creating an NPM Package
  6. Documentation Standards
  7. Testing Strategy
  8. Publishing and Distribution
  9. Best Practices and Lessons Learned

Introduction

This article documents the creation of web-window-manager, a comprehensive JavaScript library that brings desktop-like window management capabilities to web applications. We'll explore the architectural decisions, implementation details, and the process of packaging and distributing the library through NPM.

Project Goals

  • Create a lightweight, dependency-free window management system
  • Provide an intuitive API that mirrors desktop OS conventions
  • Ensure accessibility and performance across modern browsers
  • Build a foundation that developers can extend for their specific needs

Design Philosophy and Architecture

Core Design Principles

  1. Progressive Enhancement: The library should work without any build tools or frameworks
  2. Composability: Each component should function independently while integrating seamlessly
  3. Performance First: Minimize reflows and repaints through efficient DOM manipulation
  4. Accessibility: Ensure keyboard navigation and screen reader compatibility
  5. Extensibility: Provide hooks and events for custom functionality

Architectural Decisions

Why Vanilla JavaScript?

We chose vanilla JavaScript over a framework-specific implementation for several reasons:

  • Universal Compatibility: Works with any framework or no framework at all
  • Minimal Overhead: No virtual DOM or framework abstractions
  • Learning Curve: Developers familiar with DOM APIs can immediately understand the codebase
  • Performance: Direct DOM manipulation when done correctly can outperform framework abstractions

Component Architecture

WindowManager
├── Window System
│   ├── Window Creation
│   ├── Drag & Drop Handler
│   ├── Resize Handler
│   └── Focus Management
├── Context Menu System
│   ├── Menu Renderer
│   └── Position Calculator
├── Modal System
│   ├── Overlay Manager
│   └── Modal Renderer
└── Notification System
    ├── Queue Manager
    └── Animation Controller
Enter fullscreen mode Exit fullscreen mode

Development Process

Step 1: Requirements Gathering

We identified key features by analyzing popular desktop environments:

  • Windows: Title bar, control buttons, resize handles
  • macOS: Traffic light controls, smooth animations
  • Context Menus: Right-click functionality with nested menus
  • Modals: Focus trapping and backdrop interaction
  • Notifications: Toast-style alerts with auto-dismiss

Step 2: API Design

We followed a builder pattern approach for flexibility:

// Simple usage
wm.createWindow({ title: 'My App' });

// Advanced usage
wm.createWindow({
    title: 'Advanced Window',
    width: 600,
    height: 400,
    position: { x: 100, y: 100 },
    resizable: true,
    onClose: () => saveState(),
    content: document.getElementById('app-content')
});
Enter fullscreen mode Exit fullscreen mode

Step 3: Implementation Strategy

  1. Core Window Class: Established the base window functionality
  2. Event System: Implemented a pub/sub pattern for window events
  3. Interaction Handlers: Added drag, resize, and focus management
  4. Visual Components: Created context menus, modals, and notifications
  5. Style System: Developed a themeable CSS architecture

Core Components Implementation

Window Management System

The window system uses a Map to track windows and their states:

class WindowManager {
    constructor(options = {}) {
        this.windows = new Map();
        this.config = { ...DEFAULT_CONFIG, ...options };
        this.zIndexManager = new ZIndexManager();
        this.eventBus = new EventEmitter();
        this.init();
    }

    createWindow(options) {
        const window = new Window(this, options);
        this.windows.set(window.id, window);
        this.eventBus.emit('window:created', window);
        return window;
    }
}
Enter fullscreen mode Exit fullscreen mode

Drag and Drop Implementation

We implemented drag handling using pointer events for better touch support:

class DragHandler {
    constructor(window, handle) {
        this.window = window;
        this.handle = handle;
        this.isDragging = false;
        this.dragStart = { x: 0, y: 0 };
        this.windowStart = { x: 0, y: 0 };

        this.bindEvents();
    }

    bindEvents() {
        this.handle.addEventListener('pointerdown', this.onPointerDown);
        document.addEventListener('pointermove', this.onPointerMove);
        document.addEventListener('pointerup', this.onPointerUp);
    }

    onPointerDown = (e) => {
        this.isDragging = true;
        this.dragStart = { x: e.clientX, y: e.clientY };
        this.windowStart = {
            x: this.window.position.x,
            y: this.window.position.y
        };
        this.handle.setPointerCapture(e.pointerId);
    }
}
Enter fullscreen mode Exit fullscreen mode

Context Menu System

The context menu system calculates optimal positioning:

class ContextMenu {
    constructor(items, options = {}) {
        this.items = items;
        this.options = options;
        this.element = this.render();
        this.positionMenu();
    }

    positionMenu() {
        const { x, y } = this.options.position;
        const menuRect = this.element.getBoundingClientRect();
        const viewport = {
            width: window.innerWidth,
            height: window.innerHeight
        };

        // Adjust position to keep menu in viewport
        const adjustedX = Math.min(x, viewport.width - menuRect.width);
        const adjustedY = Math.min(y, viewport.height - menuRect.height);

        this.element.style.left = `${Math.max(0, adjustedX)}px`;
        this.element.style.top = `${Math.max(0, adjustedY)}px`;
    }
}
Enter fullscreen mode Exit fullscreen mode

Creating an NPM Package

Project Structure

web-window-manager/
├── src/
│   ├── core/
│   │   ├── WindowManager.js
│   │   ├── Window.js
│   │   └── EventEmitter.js
│   ├── components/
│   │   ├── ContextMenu.js
│   │   ├── Modal.js
│   │   └── Notification.js
│   ├── utils/
│   │   ├── dom.js
│   │   └── position.js
│   ├── styles/
│   │   ├── base.css
│   │   └── themes/
│   └── index.js
├── dist/
│   ├── web-window-manager.js
│   ├── web-window-manager.min.js
│   └── web-window-manager.css
├── docs/
│   ├── api/
│   ├── examples/
│   └── guides/
├── test/
├── package.json
├── README.md
├── LICENSE
└── rollup.config.js
Enter fullscreen mode Exit fullscreen mode

Package.json Configuration

{
  "name": "web-window-manager",
  "version": "1.0.0",
  "description": "A modern window management library for web applications",
  "main": "dist/web-window-manager.js",
  "module": "src/index.js",
  "style": "dist/web-window-manager.css",
  "files": [
    "dist",
    "src",
    "README.md",
    "LICENSE"
  ],
  "scripts": {
    "build": "rollup -c",
    "dev": "rollup -c -w",
    "test": "jest",
    "test:watch": "jest --watch",
    "lint": "eslint src/**/*.js",
    "docs": "jsdoc -c jsdoc.config.json",
    "prepublishOnly": "npm run build && npm test"
  },
  "keywords": [
    "window-manager",
    "desktop",
    "ui",
    "windowing",
    "modal",
    "context-menu",
    "draggable",
    "resizable"
  ],
  "author": "Your Name <your.email@example.com>",
  "license": "MIT",
  "repository": {
    "type": "git",
    "url": "https://github.com/yourusername/web-window-manager.git"
  },
  "bugs": {
    "url": "https://github.com/yourusername/web-window-manager/issues"
  },
  "homepage": "https://github.com/yourusername/web-window-manager#readme",
  "devDependencies": {
    "@rollup/plugin-node-resolve": "^15.0.0",
    "@rollup/plugin-terser": "^0.4.0",
    "eslint": "^8.0.0",
    "jest": "^29.0.0",
    "jsdoc": "^4.0.0",
    "rollup": "^3.0.0",
    "rollup-plugin-css-only": "^4.0.0"
  },
  "peerDependencies": {},
  "engines": {
    "node": ">=14.0.0"
  }
}
Enter fullscreen mode Exit fullscreen mode

Build Configuration (Rollup)

// rollup.config.js
import resolve from '@rollup/plugin-node-resolve';
import terser from '@rollup/plugin-terser';
import css from 'rollup-plugin-css-only';

export default [
  // ES Module build
  {
    input: 'src/index.js',
    output: {
      file: 'dist/web-window-manager.esm.js',
      format: 'es',
      sourcemap: true
    },
    plugins: [resolve()]
  },
  // UMD build
  {
    input: 'src/index.js',
    output: {
      file: 'dist/web-window-manager.js',
      format: 'umd',
      name: 'WindowManager',
      sourcemap: true
    },
    plugins: [resolve()]
  },
  // Minified UMD build
  {
    input: 'src/index.js',
    output: {
      file: 'dist/web-window-manager.min.js',
      format: 'umd',
      name: 'WindowManager',
      sourcemap: true
    },
    plugins: [resolve(), terser()]
  },
  // CSS
  {
    input: 'src/styles/index.js',
    output: {
      file: 'dist/web-window-manager.css',
      format: 'es'
    },
    plugins: [css({ output: 'web-window-manager.css' })]
  }
];
Enter fullscreen mode Exit fullscreen mode

Documentation Standards

API Documentation (JSDoc)

/**
 * Creates a new window instance
 * @param {Object} options - Window configuration options
 * @param {string} options.title - Window title
 * @param {number} [options.width=400] - Window width in pixels
 * @param {number} [options.height=300] - Window height in pixels
 * @param {Object} [options.position] - Initial window position
 * @param {number} [options.position.x=100] - X coordinate
 * @param {number} [options.position.y=100] - Y coordinate
 * @param {boolean} [options.resizable=true] - Enable window resizing
 * @param {boolean} [options.draggable=true] - Enable window dragging
 * @param {Function} [options.onClose] - Close event handler
 * @returns {Window} The created window instance
 * @fires WindowManager#window:created
 * @example
 * const window = wm.createWindow({
 *   title: 'My Application',
 *   width: 600,
 *   height: 400,
 *   onClose: () => console.log('Window closed')
 * });
 */
createWindow(options = {}) {
    // Implementation
}
Enter fullscreen mode Exit fullscreen mode

README Structure

# Web Window Manager

A modern, lightweight window management library for web applications.

## Features

- 🪟 **Draggable Windows** - Smooth window dragging with touch support
- 📐 **Resizable Windows** - Resize from any edge or corner
- 🎨 **Themeable** - CSS variables for easy customization
-**Accessible** - Full keyboard navigation and ARIA support
- 📱 **Responsive** - Works on desktop and mobile devices
- 🚀 **Performant** - Optimized rendering and minimal reflows
- 🔧 **Framework Agnostic** - Works with any or no framework

## Installation

Enter fullscreen mode Exit fullscreen mode


bash
npm install web-window-manager


## Quick Start

Enter fullscreen mode Exit fullscreen mode


javascript
import WindowManager from 'web-window-manager';
import 'web-window-manager/dist/web-window-manager.css';

const wm = new WindowManager();

const window = wm.createWindow({
title: 'Hello World',
content: '

Welcome!

'
});

## API Reference

See [full API documentation](./docs/api.md).

## Examples

- [Basic Usage](./examples/basic.html)
- [Custom Themes](./examples/themes.html)
- [React Integration](./examples/react.html)
- [Vue Integration](./examples/vue.html)

## Browser Support

- Chrome/Edge 88+
- Firefox 78+
- Safari 14+
- iOS Safari 14+
- Chrome Android 88+

## Contributing

See [CONTRIBUTING.md](./CONTRIBUTING.md) for development setup and guidelines.

## License

MIT © [Your Name]
Enter fullscreen mode Exit fullscreen mode

Type Definitions

// types/index.d.ts
declare module 'web-window-manager' {
  export interface WindowOptions {
    title?: string;
    width?: number;
    height?: number;
    position?: { x: number; y: number };
    resizable?: boolean;
    draggable?: boolean;
    closable?: boolean;
    minimizable?: boolean;
    maximizable?: boolean;
    content?: string | HTMLElement;
    onClose?: () => void;
    onFocus?: () => void;
    onBlur?: () => void;
  }

  export interface ContextMenuItem {
    label: string;
    icon?: string;
    action?: () => void;
    disabled?: boolean;
    separator?: boolean;
    submenu?: ContextMenuItem[];
  }

  export class Window {
    id: string;
    title: string;
    position: { x: number; y: number };
    size: { width: number; height: number };

    close(): void;
    minimize(): void;
    maximize(): void;
    focus(): void;
    setTitle(title: string): void;
    setContent(content: string | HTMLElement): void;
  }

  export default class WindowManager {
    constructor(options?: WindowManagerOptions);
    createWindow(options?: WindowOptions): Window;
    closeWindow(id: string): void;
    getWindow(id: string): Window | undefined;
    getAllWindows(): Window[];
    showContextMenu(event: MouseEvent, items: ContextMenuItem[]): void;
    showModal(options: ModalOptions): void;
    showNotification(title: string, message: string, duration?: number): void;
  }
}
Enter fullscreen mode Exit fullscreen mode

Testing Strategy

Unit Tests

// test/WindowManager.test.js
import WindowManager from '../src/core/WindowManager';

describe('WindowManager', () => {
  let wm;

  beforeEach(() => {
    document.body.innerHTML = '<div id="desktop"></div>';
    wm = new WindowManager({ container: '#desktop' });
  });

  afterEach(() => {
    wm.destroy();
  });

  describe('createWindow', () => {
    test('creates window with default options', () => {
      const window = wm.createWindow();

      expect(window).toBeDefined();
      expect(window.title).toBe('New Window');
      expect(wm.windows.size).toBe(1);
    });

    test('creates window with custom options', () => {
      const options = {
        title: 'Test Window',
        width: 500,
        height: 400
      };

      const window = wm.createWindow(options);

      expect(window.title).toBe('Test Window');
      expect(window.size.width).toBe(500);
      expect(window.size.height).toBe(400);
    });
  });

  describe('window interactions', () => {
    test('focuses window on click', () => {
      const window1 = wm.createWindow();
      const window2 = wm.createWindow();

      expect(wm.activeWindow).toBe(window2);

      window1.element.dispatchEvent(new MouseEvent('mousedown'));

      expect(wm.activeWindow).toBe(window1);
    });
  });
});
Enter fullscreen mode Exit fullscreen mode

Integration Tests

// test/integration/drag-drop.test.js
import WindowManager from '../src/index';
import { simulateDrag } from './helpers';

describe('Drag and Drop Integration', () => {
  test('window can be dragged', async () => {
    const wm = new WindowManager();
    const window = wm.createWindow({
      position: { x: 100, y: 100 }
    });

    const initialPosition = { ...window.position };

    await simulateDrag(window.element.querySelector('.window-header'), {
      from: { x: 150, y: 120 },
      to: { x: 250, y: 220 }
    });

    expect(window.position.x).toBe(initialPosition.x + 100);
    expect(window.position.y).toBe(initialPosition.y + 100);
  });
});
Enter fullscreen mode Exit fullscreen mode

Publishing and Distribution

Pre-publish Checklist

  1. Version Bump: Update version in package.json following semver
  2. Changelog: Update CHANGELOG.md with new features/fixes
  3. Tests: Ensure all tests pass (npm test)
  4. Build: Generate distribution files (npm run build)
  5. Documentation: Update API docs (npm run docs)
  6. Examples: Test all examples with new version
  7. Types: Verify TypeScript definitions are accurate

Publishing to NPM

# Login to NPM
npm login

# Publish (runs prepublishOnly script automatically)
npm publish

# Tag release on GitHub
git tag v1.0.0
git push origin v1.0.0
Enter fullscreen mode Exit fullscreen mode

CDN Distribution

The package will be automatically available on CDNs:

<!-- jsDelivr -->
<script src="https://cdn.jsdelivr.net/npm/web-window-manager@1.0.0/dist/web-window-manager.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/web-window-manager@1.0.0/dist/web-window-manager.css">

<!-- unpkg -->
<script src="https://unpkg.com/web-window-manager@1.0.0/dist/web-window-manager.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/web-window-manager@1.0.0/dist/web-window-manager.css">
Enter fullscreen mode Exit fullscreen mode

Best Practices and Lessons Learned

Performance Optimization

  1. Batch DOM Operations: Group DOM changes to minimize reflows
  2. Event Delegation: Use single event listeners on parent elements
  3. RequestAnimationFrame: Throttle drag/resize operations
  4. CSS Containment: Use contain property for better rendering performance

Accessibility Considerations

  1. Keyboard Navigation: Implement focus trapping and tab order
  2. ARIA Labels: Add appropriate roles and labels
  3. Screen Reader Support: Announce window state changes
  4. High Contrast Mode: Ensure visibility in all color modes

Common Pitfalls to Avoid

  1. Memory Leaks: Always remove event listeners on window close
  2. Z-Index Wars: Use a centralized z-index management system
  3. Touch vs Mouse: Handle both pointer types consistently
  4. CSS Conflicts: Use scoped class names or CSS modules

Future Enhancements

  1. Window Snapping: Snap to screen edges and other windows
  2. Persistence: Save/restore window layouts
  3. Multi-Monitor Support: Handle different screen configurations
  4. Virtual Desktops: Multiple window spaces
  5. Plugin System: Allow third-party extensions

Conclusion

Building a window manager library requires careful consideration of performance, accessibility, and developer experience. By following modern web standards and best practices, we've created a foundation that developers can use to build sophisticated desktop-like applications in the browser.

The key to success lies in:

  • Starting with a solid architecture
  • Prioritizing performance from the beginning
  • Writing comprehensive documentation
  • Testing across different scenarios
  • Listening to community feedback

This library serves as both a practical tool and a learning resource for developers interested in creating complex UI systems for the web.

Comments 1 total

  • AdminHQ
    AdminHQJun 16, 2025

    Attention writers! If you’ve ever published on Dev.to, you may be eligible for DEV Contributor rewards. Claim your rewards here. for verified Dev.to users only. – Dev.to Community Support

Add comment