A standalone, lightweight React library that brings a complete desktop window management experience to the web.
Drag, resize, snap, minimize, maximize β all performant and mobile-ready out of the box.
npm install @maomaolabs/core
# or
yarn add @maomaolabs/core
# or
pnpm add @maomaolabs/coreRequires
reactandreact-dom>= 18.0.0 as peer dependencies.
import { WindowSystemProvider, WindowManager, useWindowActions } from '@maomaolabs/core';
import '@maomaolabs/core/dist/style.css';
const AppLauncher = () => {
const { openWindow } = useWindowActions();
return (
<button onClick={() => openWindow({
id: 'hello',
title: 'Hello World',
component: <div>Hello from a managed window!</div>
})}>
Launch App
</button>
);
};
export default function App() {
return (
<WindowSystemProvider>
<WindowManager />
<AppLauncher />
</WindowSystemProvider>
);
}
β οΈ Don't forget the CSS import β it's required for drag, resize, and snap overlays to work correctly.
The Toolbar component provides a ready-made taskbar with app launchers, folder support, and minimized window restoration.
import { WindowSystemProvider, WindowManager, Toolbar } from '@maomaolabs/core';
const DESKTOP_ITEMS = [
{
id: 'browser',
title: 'Browser',
component: <div />,
initialSize: { width: 800, height: 600 }
},
{
id: 'games-folder',
title: 'Games',
apps: [
{ id: 'minesweeper', title: 'Minesweeper', component: <div /> }
]
}
];
export default function Desktop() {
return (
<WindowSystemProvider>
<WindowManager />
<Toolbar toolbarItems={DESKTOP_ITEMS} showLogo={true} />
</WindowSystemProvider>
);
}Use useWindows when you need to render UI based on open windows (e.g., a custom taskbar or badge counter).
β οΈ Warning:useWindowstriggers a re-render on every window state change (drag, resize, focus). Only use it where necessary.
import { useWindows } from '@maomaolabs/core';
const OpenAppCounter = () => {
const windows = useWindows();
return <div>Active windows: {windows.length}</div>;
};| Component | Description | Props |
|---|---|---|
WindowSystemProvider |
Root context provider. Wrap your entire app with this. | children: ReactNode, systemStyle?: SystemStyle |
WindowManager |
Renders all active windows and snap preview overlays. | β |
Toolbar |
Taskbar with app launchers and folder support. | toolbarItems: ToolbarItem[], showLogo?: boolean |
Returns window manipulation methods. Does not subscribe to window state β safe to call anywhere without performance concerns.
| Method | Signature | Description |
|---|---|---|
openWindow |
(window: WindowDefinition) => void |
Opens a new window, or focuses it if already open. |
closeWindow |
(id: string) => void |
Destroys a window instance. |
focusWindow |
(id: string) => void |
Brings a window to the top of the z-index stack. |
updateWindow |
(id: string, data: Partial<WindowInstance>) => void |
Patches an existing window's state. |
Returns WindowInstance[] β the list of all currently active windows. Re-renders on every state change.
Returns { snapPreview, setSnapPreview } for reading and controlling the active snap preview overlay.
| Property | Type | Required | Description |
|---|---|---|---|
id |
string |
β | Unique identifier for the window. |
title |
string |
β | Text shown in the window title bar. |
component |
ReactNode |
β | Content rendered inside the window. |
icon |
ReactNode |
β | Icon shown in the title bar and toolbar. |
initialSize |
{ width: number; height: number } |
β | Starting dimensions in pixels. |
initialPosition |
{ x: number; y: number } |
β | Starting coordinates in pixels. |
layer |
'base' | 'normal' | 'alwaysOnTop' | 'modal' |
β | Z-index render layer. |
isMaximized |
boolean |
β | Spawns the window in maximized state. |
canMinimize |
boolean |
β | Shows the minimize control. |
canMaximize |
boolean |
β | Shows the maximize/restore control. |
canClose |
boolean |
β | Shows the close control. |
className |
string |
β | Inject custom CSS classes directly into the window container. |
style |
React.CSSProperties |
β | Inject inline styles overriding or extending window container styles. |
| Property | Type | Required | Description |
|---|---|---|---|
id |
string |
β | Unique identifier for the folder. |
title |
string |
β | Folder display name. |
apps |
WindowDefinition[] |
β | Windows grouped inside this folder. |
icon |
ReactNode |
β | Optional visual icon. |
ToolbarItem = WindowDefinition | FolderDefinition
Exported type available for reuse in your own components:
import type { WindowStyling } from '@maomaolabs/core';
// { className?: string; style?: React.CSSProperties }The library requires a single CSS import to function correctly:
import '@maomaolabs/core/dist/style.css';Ensure your bundler (Vite, Webpack, etc.) is configured to process CSS from node_modules.
The context provider accepts a systemStyle prop that governs the aesthetics of the entire rendered window manager system:
<WindowSystemProvider systemStyle="aero">Pre-bundled themes include:
defaulttraffic(colored dot buttons concept)linux(modern dark/light gradient adaptation)yk2000(classic 90s/00s retro styling)aero(translucent glass blurring)
Note on Custom Themes: SystemStyle strictly autocompletes the pre-built themes above, but mathematically permits any string to be passed via Type relaxation. You can pass your own systemStyle="my-custom-theme" alongside injected custom CSS.
You can define your own theme by creating a CSS file that targets the data-system-style attribute.
β οΈ Use standard CSS attribute selectors β avoid:global()unless your bundler explicitly supports it (e.g. CSS Modules with PostCSS).
/* my-custom-theme.css */
[data-system-style="my-custom-theme"] .window-header {
background: #1a1a2e;
color: #e0e0e0;
}
[data-system-style="my-custom-theme"] .window-controls {
gap: 6px;
}Import the CSS file anywhere in your app (e.g. src/index.tsx) before the provider renders:
import './my-custom-theme.css';Then pass the identifier to the provider:
<WindowSystemProvider systemStyle="my-custom-theme">
{/* ... */}
</WindowSystemProvider>The following global class names are always present on the window DOM and safe to target in your theme:
| Selector | Element |
|---|---|
.window-container |
Root window wrapper |
.window-header |
Title bar (drag area) |
.window-title |
Title text container |
.window-icon |
Icon inside the title bar |
.window-controls |
Button group (minimize / maximize / close) |
.terminal-btn |
Generic control button |
.window-scrollbar |
Scrollable content area |
.window-resize-handle |
Bottom-right resize grip |
You can also target individual buttons via the data-action attribute:
[data-system-style="my-custom-theme"] [data-action="close"] { background: red; }
[data-system-style="my-custom-theme"] [data-action="maximize"] { background: green; }
[data-system-style="my-custom-theme"] [data-action="minimize"] { background: yellow; }Custom className and style props are accepted on each individual window definition via openWindow(), allowing per-instance overrides on top of the global theme:
openWindow({
id: 'my-app',
title: 'My App',
component: <div />,
className: 'my-extra-class',
style: { borderRadius: '16px', border: '1px solid #444' },
});These are merged after the global theme styles, so they always take precedence.
npm install # Install dependencies
npm run dev # Start dev server with hot reload
npm run test # Run test suite (Vitest)PRs are welcome. Please ensure all tests pass before submitting.
MIT Β© MaoMao Labs






