Launcher
The launcher is the keyboard front door: type a few letters, get the right window. Every OS presents this differently, so the library splits it into a shared brain and a swappable face. The data (apps, system windows, and registerSpotlightSource rows), the Cmd-K shortcut, selection, and activation are the same in every register; theme.chrome.launcher picks the layout.
Presentations
Section titled “Presentations”theme.chrome.launcher chooses the face. All three carry the same results and filter the same way.
| Value | Reads as | Layout |
|---|---|---|
"spotlight" (default) | macOS Spotlight | A centered command palette: search field over a vertical result list. |
"grid" | GNOME Activities | A full-bleed overview: a centered search field over a grid of large app icons. |
"menu" | Windows Start | A panel raised from the dock launcher: a search field over a grid of app tiles. |
The default theme uses "spotlight", Ubuntu uses "grid", and Windows uses "menu". The arrow keys navigate every register (the grid and menu add left/right); Enter activates; Escape dismisses and restores focus.
Import
Section titled “Import”import { Launcher, useLauncher, SPOTLIGHT_OPEN_EVENT } from "@react-ui-os/desktop";<Launcher> is mounted by the default <Desktop>. <Spotlight> is still exported as a back-compat alias of <Launcher>.
Opening the launcher
Section titled “Opening the launcher”| Trigger | Behavior |
|---|---|
Cmd-K (macOS) / Ctrl-K (elsewhere) | Toggles it. Bails when typing in an input or textarea. |
window.dispatchEvent(new CustomEvent(SPOTLIGHT_OPEN_EVENT)) | Opens from any component without prop drilling. |
| The dock launcher button | Dispatches the event above. The bar dock shows it; the menu and grid pop where the OS does. |
Result kinds
Section titled “Result kinds”| Kind | Source |
|---|---|
| App | Every entry in the apps prop passed to <Desktop> / <DesktopProvider>. |
| System | Every entry in the systemWindows registry (Settings by default, plus any you register). |
| External | Every result returned by a function registered via registerSpotlightSource. |
Activating an App or System result calls openWindow(...), the same primitive a dock click uses. External results run their own onActivate so they can navigate, dispatch, or open a URL.
Adding your own results
Section titled “Adding your own results”Use registerSystemWindow(...) when activating the result should open a window managed by react-ui-os. Settings is the canonical example.
Use registerSpotlightSource(...) when activating should do something else: navigate to a docs page, open a URL, dispatch an event. A source is (query) => SpotlightResult[], and each result owns its onActivate. Sources feed every presentation, not just Spotlight.
import { registerSpotlightSource } from "@react-ui-os/desktop";
useEffect(() => { return registerSpotlightSource("bookmarks", (query) => { if (!query) return []; return bookmarks .filter((b) => b.name.toLowerCase().includes(query)) .map((b) => ({ id: b.id, name: b.name, tagline: b.url, kindLabel: "Bookmark", onActivate: () => window.open(b.url, "_blank", "noopener"), })); });}, []);A custom launcher: useLauncher
Section titled “A custom launcher: useLauncher”When the three presentations do not fit, build your own face on the same brain. useLauncher() returns the open state, the query, the merged and filtered results, the selection, and activate / moveSelection / close. It also owns the Cmd-K toggle and the open event, so a custom launcher gets those for free. Render it at depth 2 in place of <Launcher>.
import { useLauncher } from "@react-ui-os/desktop";
function MyLauncher() { const { open, query, setQuery, results, activate, close } = useLauncher(); if (!open) return null; return ( <div role="dialog" aria-label="Launcher"> <input value={query} onChange={(e) => setQuery(e.target.value)} autoFocus /> {results.map((r) => ( <button key={r.key} onClick={() => activate(r)}> {r.name} </button> ))} <button onClick={close}>Close</button> </div> );}Accessibility
Section titled “Accessibility”- The search field is a
role="combobox"wired to its results listbox witharia-activedescendant, so screen readers announce the highlighted result as the arrows move it. - The Spotlight backdrop is
role="presentation"with click-to-dismiss; the panels arerole="dialog". - Each result is a
role="option"witharia-selected. - Focus restores on close and is never trapped.
See also
Section titled “See also”- Themes overview: the
chrome.launchertoken. - registerSpotlightSource: contribute findable rows.
- registerSystemWindow: surface custom windows.