# How to Add a Custom Bar Widget to the Omarchy Top Bar

> Easily add a custom bar widget to the Omarchy top bar by creating a QML component and placing it in the correct directory. Omarchy automatically discovers and loads your widget.

- Repository: [37signals/omarchy](https://github.com/basecamp/omarchy)
- Tags: how-to-guide
- Published: 2026-08-28

---

**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`.

```qml
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:

```jsonc
{
  "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`:

```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.

```qml
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:

```jsonc
{
  "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 from `shell/Ui/BarWidget.qml` and set the `anchor` property to `"left"`, `"center"`, or `"right"` to control positioning in the top bar.
- **Register via `manifest.jsonc`**: Use `type: "bar-widget"` for top bar items or `type: "inline-module"` for panel-embedded components to enable automatic discovery by the registry service.
- **Leverage `BarWidgetRegistry`**: The `shell/services/BarWidgetRegistry.qml` service 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 in `shell/plugins/bar/inline/` or within specific panel plugin directories.
- **Reference existing implementations**: Study `shell/plugins/panels/weather/BarWidget.qml` and `shell/plugins/menu/BarWidget.qml` for 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.