desktop entry of appSurfaces. For a phone-style app that also runs on desktop, StackNavigator adapts to desktop by itself.
DesktopWindow
The window layout. Only the content scrolls; the chrome around it stays put. It hides the shell’s own header (the toolbar takes its place) and leaves room for the macOS window buttons.ReactNode
The source list down the left, usually a
SourceList.ReactNode
The bar over the content, usually a
Toolbar.ReactNode
The pane on the right for the selection. Pass nothing to close it.
ReactNode
A thin bar along the bottom: counts, sync state.
string
Remember pane widths and whether the sidebar is shown, in
localStorage. Leave it out to start fresh every time.{ initial?, min?, max? }
default:"220 / 170 / 340"
Sidebar width limits in px.
{ initial?, min?, max? }
default:"300 / 240 / 460"
Inspector width limits in px.
useDesktopWindow() returns { os, sidebarHidden, toggleSidebar, hasSidebar }. Outside one, useDesktopOS() still tells you the idiom: 'macos' or 'windows'.
Toolbar
ReactNode
The window’s title: the place or the thing open.
ReactNode
A quieter line beside it, such as “42 items”.
ReactNode
Controls before the title, such as back and forward.
ReactNode
Buttons, a search field and segmented controls, at the trailing end in order.
string
required
Its name: the tooltip, and the text with
showLabel or without an icon.() => void
required
Click handler.
IconName
Button icon.
boolean
Text beside the icon, for the window’s main action.
boolean
The main action, in the accent color.
boolean
A toggle that’s on, such as a view mode.
string
A key combination that presses it, shown in the tooltip, such as
mod+n.boolean
default:"true"
Bind
shortcut here. Turn it off when useDesktopCommands already binds the same key.boolean
Greyed out.
value, onChange, placeholder? (default “Search”), onSubmit? and shortcut? (default mod+f; false for none). ToolbarGroup (label?) groups related buttons, and ToolbarSeparator draws a divider.
SourceList
The sidebar’s list of places, like Finder’s or Mail’s. The list is a single Tab stop; ↑ and ↓ move between rows, and Return or Space opens one.label (required, for screen readers), footer? (pinned under the list).
SourceListSection: title?, collapsible? (a disclosure on the title, as in Finder), defaultCollapsed?, action? (shown on hover at the title’s end, such as a ”+”).
SourceListItem: label, onSelect (required), icon? or leading? (an avatar or cover), selected?, count?, shortcut? (shown on hover), disabled?. For a right-click menu, wrap it in a ContextMenu.
SelectionList
A list (or grid) with desktop selection: click selects, ⌘ / Ctrl-click and Shift-click extend it, ⌘A selects all, double-click or Return opens. Typing a few letters jumps to a matching row.T[]
required
The rows’ data.
(item) => string
required
A stable key per item.
string[]
required
The selected keys.
(keys: string[]) => void
required
The selection changed.
(item, { selected }) => ReactNode
required
Draws a row or tile.
string
required
What the list is, for screen readers.
boolean
Allow more than one selected item.
(item) => void
Double-click, or Return on the selection.
Right-click menu. A row outside the selection is selected first, so the menu always acts on what’s highlighted.
(item) => string
Text for type-to-jump.
ReactNode
Shown when there are no items.
number
Row height in px. Defaults to the platform’s: 28 on macOS, 32 on Windows.
'list' | 'grid'
default:"'list'"
grid lays items out as tiles, like a photo library: ← and → step through tiles, ↑ and ↓ move a row.number
default:"160"
The narrowest a tile gets in
grid, in px.Inspector
The pieces of an inspector pane, shaped like Finder’s Get Info:useDesktopCommands
Declare the window’s commands once. On macOS they appear in your app’s menu in the system menu bar, where the shell turns their keys into menu clicks. Everywhere else (the Windows shell, a browser) they are bound as keyboard shortcuts in the page.id, label, run, and optionally shortcut, enabled (default true; a disabled command’s key does nothing) and checked. A key without a modifier, such as delete, is always bound in the page, because the menu bar never carries one. A toolbar button for the same command should pass bindShortcut={false} so the key isn’t handled twice.
This builds on the SDK’s useAppMenu.
Drag and drop
Mouse and trackpad drag and drop, desktop style. None of it gets in the way of touch; phones use swipe rows and context menus for the same jobs. Files from the desktop: wrap the target inDropZone. While files hover, it gets data-dropping and shows hint.
DropZone takes onFiles (required), accept? (MIME patterns, as in <input accept>), single?, disabled?, hint?, className? and style?.
Your own items: make an element draggable with useDragSource(kind, data) and a target with useDropTarget(kind, onDrop, { canDrop? }). Spread the result on the element. While something droppable hovers, the target has data-drop-over.