How to Add a Custom Bar Widget to the Omarchy Top Bar
To add a custom bar widget to the Omarchy top bar, create a QML component that extends BarWidget, place it in the shell/plugins/bar/widgets/ directory with a manifest.jsonc file, and the BarWidgetRegistry service will automatically discover and instantiate it at startup.
Omarchy is the open-source desktop shell developed by Basecamp (37signals), built with Qt Quick and QML. Its modular top bar system uses a declarative BarWidget architecture that requires no C++ or JavaScript—only QML and a minimal configuration file—to extend with custom functionality.
Creating the Bar Widget Component
Omarchy widgets are fully declarative QML components. To create one, you extend the base BarWidget component and define your UI logic.
Implementing the BarWidget Interface
Create a new .qml file in shell/plugins/bar/widgets/ that imports Omarchy.Ui 1.0 and extends BarWidget. The base component, defined in shell/Ui/BarWidget.qml, provides required properties including anchor (positioning as "left", "center", or "right"), width, height, and visible.
import QtQuick 2.15
import QtQuick.Layouts 1.15
import Omarchy.Ui 1.0
BarWidget {
id: root
width: 48
height: 48
anchor: "right"
MouseArea {
anchors.fill: parent
onClicked: root.toggle()
}
Image {
anchors.centerIn: parent
source: root.active ? "qrc:/icons/check.svg" : "qrc:/icons/close.svg"
}
}
Widget Properties and Anchoring
The anchor property determines the widget's position in the top bar flow. Use "left" for the leading edge (near the app menu), "center" for the middle section, or "right" for the trailing edge (near system trays). The BarWidget base class handles layout insertion automatically based on this property, while built-in examples like shell/plugins/bar/widgets/Workspaces.qml demonstrate complex state interactions.
Registering with BarWidgetRegistry
The BarWidgetRegistry service located at shell/services/BarWidgetRegistry.qml manages widget lifecycle and discovery. It scans plugin directories at startup and instantiates any valid BarWidget components it discovers.
Automatic Discovery via Manifest
Create a manifest.jsonc file alongside your QML component to register the widget:
{
"name": "my-widget",
"description": "A tiny custom widget for the top bar",
"type": "bar-widget",
"entry": "MyWidget.qml"
}
The registry recognizes the bar-widget type and loads the entry point automatically. No manual registration code is required for files placed in shell/plugins/bar/widgets/.
Explicit Registration (Optional)
For external plugins or development overrides, explicitly list widgets in the registry's pluginList property within shell/services/BarWidgetRegistry.qml:
property var pluginList: [
// …existing entries…
"plugins/bar/widgets/MyWidget.qml"
]
Adding Inline Modules to Panels
Inline modules differ from bar widgets—they render inside existing panels (such as the Menu or Weather panels) rather than the top bar row itself. These typically reside in shell/plugins/bar/inline/ or within specific panel directories.
Creating an Inline Module
Inline modules use standard QML components rather than the BarWidget base class. They are inserted into Row or Column layouts within panel definitions. Reference shell/plugins/menu/BarWidget.qml for an example of inline usage within the Omarchy menu panel.
import Omarchy.Ui 1.0
Panel {
// …panel boilerplate…
Row {
MyInlineWidget { }
}
}
Inline Module Manifest
Use type: "inline-module" in your manifest to distinguish these from top bar widgets:
{
"name": "my-inline",
"description": "Inline module for the Omarchy menu",
"type": "inline-module",
"entry": "MyInline.qml"
}
Study shell/plugins/panels/weather/Panel.qml for panel layout patterns and shell/plugins/panels/weather/BarWidget.qml for a complete reference implementation combining both widget types.
Summary
- Extend
BarWidget: Create a QML file that inherits fromshell/Ui/BarWidget.qmland set theanchorproperty to"left","center", or"right"to control positioning in the top bar. - Register via
manifest.jsonc: Usetype: "bar-widget"for top bar items ortype: "inline-module"for panel-embedded components to enable automatic discovery by the registry service. - Leverage
BarWidgetRegistry: Theshell/services/BarWidgetRegistry.qmlservice handles instantiation automatically—no C++ compilation or manual JavaScript registration is required. - Place files correctly: Bar widgets belong in
shell/plugins/bar/widgets/; inline modules belong inshell/plugins/bar/inline/or within specific panel plugin directories. - Reference existing implementations: Study
shell/plugins/panels/weather/BarWidget.qmlandshell/plugins/menu/BarWidget.qmlfor complex interaction patterns and state management.
Frequently Asked Questions
What is the BarWidget base component?
BarWidget is a QML component defined in shell/Ui/BarWidget.qml that provides the required interface for all top bar widgets. It exposes properties like anchor (for positioning), width, height, and visible, and handles lifecycle management with the BarWidgetRegistry service. All custom widgets must extend this component to be recognized by the system.
Where do I place custom bar widget files?
Place custom bar widget QML files and their manifest.jsonc configurations in shell/plugins/bar/widgets/. The BarWidgetRegistry service scans this directory at startup. For inline modules intended for specific panels, use shell/plugins/bar/inline/ or the individual panel's plugin directory (e.g., shell/plugins/panels/weather/).
Can I add widgets to existing panels like the Menu?
Yes. Create an inline module with type: "inline-module" in your manifest instead of bar-widget. These modules render inside panel layouts rather than the top bar row. Reference shell/plugins/menu/BarWidget.qml for an example of a widget that lives inside the Omarchy menu panel, or examine shell/plugins/panels/weather/Panel.qml for panel layout patterns.
Do I need to write C++ or JavaScript to create widgets?
No. The Omarchy BarWidget system is fully declarative. You only need QML for the UI component and a manifest.jsonc file for registration. The BarWidgetRegistry handles all instantiation and lifecycle management automatically without requiring compiled C++ code or imperative JavaScript registration logic.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →