Skip to content

Desktop

The Desktop component is the one-line entry point. It wraps the provider stack and composes the default surfaces. Use it when you want the full chrome; drop down to DesktopProvider when you need to pick and choose.

Desktop in action Open in new tab ↗
import { Desktop } from "@react-ui-os/desktop";
import { macosTheme } from "@react-ui-os/theme-macos";
import type { App } from "@react-ui-os/core";
const apps: App[] = [{ id: "notes", name: "Notes", content: () => <h1>Notes</h1> }];
<Desktop apps={apps} theme={macosTheme} brand="acme" />;

Desktop composes these surfaces in order. To swap any of them, use DesktopProvider and write your own composition.

<DesktopProvider apps={apps} theme={theme} storage={storage}>
<Wallpaper />
<MenuBar brand={brand} />
<DesktopIcons />
<WindowLayer />
<Dock />
<KeyboardShortcuts />
<Spotlight />
</DesktopProvider>
PropTypeDefaultDescription
appsApp[]requiredThe app registry. Order matters: Cmd-1..9 maps to indices, dock tiles render in this order.
themeOsThemerequiredThe active theme. Pass macosTheme or call createWindowsTheme(...).
brandstringnoneOptional label on the left of the menu bar (the macOS Apple-menu slot). Hidden when omitted, so the library never stamps its own name on your desktop.
storageStorageAdapterlocalStorageBackend for user preferences and state-earned folders. Defaults to a localStorage-backed adapter; swap for a server adapter to sync across devices.
childrenReactNodeundefinedHeadless companions rendered inside the provider alongside the default surfaces. Use for URL sync, deep-link activators, analytics, or any component that needs useWindowManager().
const apps = [{ id: "hello", name: "Hello", content: () => <h1>Hello</h1> }];
<Desktop apps={apps} theme={macosTheme} />;
import { createWindowsTheme } from "@react-ui-os/theme-windows";
const theme = createWindowsTheme({ wallpaperSrc: "/windows-wallpaper.jpg" });
<Desktop apps={apps} theme={theme} brand="acme.studio" />;

Mount a deep-link activator inside the provider so it can call openWindow(...) directly. This is how the playground reads ?demo=spotlight and opens Spotlight on boot.

function DemoActivator() {
const { openWindow } = useWindowManager();
useEffect(() => {
const demo = new URLSearchParams(location.search).get("demo");
if (demo === "settings") openWindow({ kind: "system", systemId: "settings" });
}, [openWindow]);
return null;
}
<Desktop apps={apps} theme={theme}>
<DemoActivator />
</Desktop>;

Server-backed prefs so a user’s accent + dock position follow them across devices:

import type { StorageAdapter } from "@react-ui-os/core";
const remoteStorage: StorageAdapter = {
get: (key) => fetchPref(key),
set: (key, value) => savePref(key, value),
remove: (key) => deletePref(key),
subscribe: (listener) => sse("/prefs", listener),
};
<Desktop apps={apps} theme={theme} storage={remoteStorage} />;
  • The menu bar is rendered as a <header> and the dock as a <nav aria-label="App dock">.
  • Every window is wrapped in role="region" with an aria-label of “<Name> window”.
  • Traffic lights have aria-label values of “Close”, “Minimize”, “Maximize”.
  • The Spotlight palette is role="dialog" aria-modal="true" with a labelled listbox.
  • Reduced-motion preferences disable the wallpaper parallax.
  • Mod + / or Ctrl + ? (and the right-click desktop menu, for layouts where the / key needs Shift) opens a Keyboard Shortcuts reference listing every binding. Because a web page can’t receive the OS-reserved chords (Win/Super+Arrow, Cmd+Arrow on macOS), shortcuts use the page-reachable Mod key; the full registry and a build-time conflict test live in keymap.ts.