Skip to content

Status items

Status items are the small widgets in the menu bar’s right cluster. The library hard-codes none of them. The registry is a plug-in point. Each registered item gets a slot between the workspace pips and the clock; click handlers, tooltips, and badges all wire through the same primitives every other library surface uses.

Notice the green dot and the ♪ next to the clock: both registered via registerStatusItem Open in new tab ↗
import {
registerStatusItem,
unregisterStatusItem,
type StatusItem,
} from "@react-ui-os/desktop";
const unsub = registerStatusItem({
id: "battery",
icon: <BatteryIcon level={0.78} />,
tooltip: "Battery 78%, 3h 12m remaining",
badge: 78, // shows a small "78" pill on the icon
onClick: openBatteryPopover,
order: 50, // lower = further from the clock
});

registerStatusItem returns an unsubscribe. Re-registering the same id replaces the previous record, so a host component can update its badge or icon without churn.

FieldTypeDescription
idstringStable id used as the React key and the dedup token.
iconReactNodeVisible icon: ~14 px. Use your icon kit.
tooltipstringHover tooltip body.
badgestring | numberSmall pill rendered on top of the icon. Falsy values hide it.
shortcutstringDecorative shortcut hint in the tooltip (”⌃⇧Space”).
onClick() => voidActivation handler. If omitted, the item is non-interactive.
ordernumberRender order. Lower = further from the clock. Default 100.
  • Reach for registerStatusItem when the widget should be persistent and system-wide: it lives in the menu bar regardless of which app is focused.
  • Reach for <Tooltip> directly when you’re decorating an in-window button or any element that doesn’t belong in the system chrome.

When the widget’s contents change (battery percentage, sync progress), have its host component re-register on every change:

import { useEffect } from "react";
import { registerStatusItem } from "@react-ui-os/desktop";
export function BatteryStatusItem() {
const level = useBatteryLevel();
useEffect(() => {
return registerStatusItem({
id: "battery",
icon: <BatteryIcon level={level} />,
tooltip: `Battery ${String(Math.round(level * 100))}%`,
badge: Math.round(level * 100),
order: 50,
});
}, [level]);
return null;
}

Mount <BatteryStatusItem /> once anywhere inside <DesktopProvider>. The registry handles the rest.

  • The tray is role="toolbar" aria-label="Status tray".
  • Each item is a <button> with the tooltip text as its aria-label. Even keyboard-only users get the same hint hover users see.
  • Items without an onClick render as disabled buttons so tabbing skips them but they still announce.