Skip to main contentSkip to navigation

Desktop Hooks

React hooks for building macOS-style desktop interfaces with window management, settings, and keyboard shortcuts

Installation

Run the following command:

npx @hanzo/ui@latest add desktop

Hooks

useWindowManager

Manages multiple windows with open/close state, built on React's useReducer pattern.

import { useWindowManager } from "@hanzo/ui/desktop"

function Desktop() {
  const windows = useWindowManager()

  return (
    <div>
      <button onClick={() => windows.openWindow("Settings")}>
        Open Settings
      </button>
      <button onClick={() => windows.toggleWindow("Terminal")}>
        Toggle Terminal
      </button>
      <button onClick={() => windows.closeAllWindows()}>Close All</button>

      {windows.isOpen("Settings") && (
        <Window
          title="Settings"
          onClose={() => windows.closeWindow("Settings")}
        >
          ...
        </Window>
      )}

      {windows.isOpen("Terminal") && (
        <Window
          title="Terminal"
          onClose={() => windows.closeWindow("Terminal")}
        >
          ...
        </Window>
      )}
    </div>
  )
}

API

MethodTypeDescription
isOpen(id: string) => booleanCheck if a window is open
openWindow(id: string) => voidOpen a window
closeWindow(id: string) => voidClose a window
toggleWindow(id: string) => voidToggle a window's open state
closeAllWindows() => voidClose all windows
focusWindow(id: string) => voidFocus/activate a window
activeWindowstring | nullCurrently active window
openWindowsstring[]List of all open window IDs
windowsRecord<string, boolean>Window state map

useDesktopSettings

Manages desktop settings with localStorage persistence.

import { useDesktopSettings } from "@hanzo/ui/desktop"

function SettingsPanel() {
  const settings = useDesktopSettings()

  return (
    <div>
      <label>
        Theme
        <select
          value={settings.theme}
          onChange={(e) => settings.setTheme(e.target.value)}
        >
          <option value="light">Light</option>
          <option value="dark">Dark</option>
          <option value="system">System</option>
        </select>
      </label>

      <label>
        <input
          type="checkbox"
          checked={settings.showDock}
          onChange={(e) => settings.setShowDock(e.target.checked)}
        />
        Show Dock
      </label>

      <label>
        Dock Position
        <select
          value={settings.dockPosition}
          onChange={(e) => settings.setDockPosition(e.target.value)}
        >
          <option value="bottom">Bottom</option>
          <option value="left">Left</option>
          <option value="right">Right</option>
        </select>
      </label>
    </div>
  )
}

API

PropertyTypeDescription
theme'light' | 'dark' | 'system'Current theme
setTheme(theme) => voidSet theme
colorSchemestringColor scheme name
setColorScheme(scheme) => voidSet color scheme
showDockbooleanWhether dock is visible
setShowDock(show) => voidToggle dock visibility
dockPosition'bottom' | 'left' | 'right'Dock position
setDockPosition(position) => voidSet dock position
dockMagnificationbooleanDock magnification enabled
setDockMagnification(enabled) => voidToggle magnification
fontSizenumberBase font size
setFontSize(size) => voidSet font size
windowTransparencynumberWindow transparency (0-1)
setWindowTransparency(opacity) => voidSet transparency
resetToDefaults() => voidReset all settings

useOverlayManager

Manages overlay/modal states like spotlight, about dialog, etc.

import { useOverlayManager } from "@hanzo/ui/desktop"

function Desktop() {
  const overlays = useOverlayManager()

  return (
    <div>
      <button onClick={() => overlays.open("spotlight")}>
        Open Spotlight (⌘+Space)
      </button>

      <button onClick={() => overlays.open("about")}>About This Mac</button>

      {overlays.isOpen("spotlight") && (
        <Spotlight onClose={() => overlays.close("spotlight")} />
      )}

      {overlays.isOpen("about") && (
        <AboutDialog onClose={() => overlays.close("about")} />
      )}
    </div>
  )
}

API

PropertyTypeDescription
overlaysOverlayStateCurrent overlay states
isOpen(id: string) => booleanCheck if an overlay is open
open(id: string) => voidOpen an overlay by id
close(id: string) => voidClose an overlay by id
toggle(id: string) => voidToggle an overlay
closeAll() => voidClose all overlays

Built-in overlay IDs: spotlight, contextMenu, modal, drawer


useKeyboardShortcuts

Register keyboard shortcuts for your desktop application.

import { useKeyboardShortcuts } from "@hanzo/ui/desktop"

function Desktop() {
  const windows = useWindowManager()
  const overlays = useOverlayManager()

  useKeyboardShortcuts([
    // ⌘+Space: Open Spotlight
    { key: ' ', meta: true, action: overlays.openSpotlight },

    // ⌘+Q: Quit active app
    { key: 'q', meta: true, action: () => windows.close(windows.activeWindow) },

    // ⌘+W: Close window
    { key: 'w', meta: true, action: () => windows.close(windows.activeWindow) },

    // ⌘+N: New window
    { key: 'n', meta: true, action: () => windows.open('NewDocument') },

    // ⌘+,: Preferences
    { key: ',', meta: true, action: () => windows.open('Settings') },

    // ⌘+Tab: App switcher
    { key: 'Tab', meta: true, action: overlays.openAppSwitcher },

    // ⌘+⌥+Esc: Force Quit
    { key: 'Escape', meta: true, alt: true, action: overlays.openForceQuit },
  ])

  return (
    // ... desktop content
  )
}

Shortcut Definition

PropertyTypeDescription
keystringKey to listen for
metabooleanRequire ⌘ (Mac) / Ctrl (Windows)
altbooleanRequire Alt/Option
shiftbooleanRequire Shift
ctrlbooleanRequire Control
action() => voidCallback when triggered

Complete Example

import {
  Spotlight,
  useDesktopSettings,
  useKeyboardShortcuts,
  useOverlayManager,
  useWindowManager,
  Window,
} from "@hanzo/ui/desktop"
import { Dock, DockItem } from "@hanzo/ui/dock"

const apps = ["Finder", "Terminal", "Safari", "Mail", "Calendar", "Settings"]

export function Desktop() {
  const windows = useWindowManager()
  const settings = useDesktopSettings()
  const overlays = useOverlayManager()

  // Register keyboard shortcuts
  useKeyboardShortcuts([
    { key: " ", meta: true, action: overlays.openSpotlight },
    { key: "q", meta: true, action: () => windows.close(windows.activeWindow) },
    { key: ",", meta: true, action: () => windows.open("Settings") },
  ])

  return (
    <div
      className="h-screen w-screen relative"
      style={{
        opacity: settings.windowTransparency,
        fontSize: settings.fontSize,
      }}
    >
      {/* Desktop Background */}
      <div className="absolute inset-0 bg-gradient-to-br from-blue-500 to-purple-600" />

      {/* Windows */}
      {apps.map(
        (app) =>
          windows.isOpen(app) && (
            <Window
              key={app}
              title={app}
              onClose={() => windows.close(app)}
              windowType={settings.theme === "dark" ? "dark" : "default"}
            >
              <div className="p-4">{app} content</div>
            </Window>
          )
      )}

      {/* Spotlight */}
      {overlays.spotlight && (
        <Spotlight
          isOpen={true}
          onClose={overlays.closeSpotlight}
          items={apps.map((app) => ({
            id: app.toLowerCase(),
            label: app,
            category: "Applications",
          }))}
          onSelect={(item) => {
            windows.open(item.label)
            overlays.closeSpotlight()
          }}
        />
      )}

      {/* Dock */}
      {settings.showDock && (
        <Dock
          position={settings.dockPosition}
          magnification={settings.dockMagnification ? 60 : 0}
        >
          {apps.map((app) => (
            <DockItem
              key={app}
              tooltip={app}
              onClick={() => windows.toggle(app)}
              isActive={windows.isOpen(app)}
            />
          ))}
        </Dock>
      )}
    </div>
  )
}