# How to Create Custom Bar Modules in the Omarchy Shell: A Complete Guide

> Learn to create custom bar modules in Omarchy shell with QML components. Follow our guide to enhance your shell experience by adding unique widgets to your bar.

- Repository: [Omacom/omarchy](https://github.com/omacom/omarchy)
- Tags: how-to-guide
- Published: 2026-08-30

---

**You can create custom bar modules in the Omarchy shell by writing QML components that export a unique `moduleName` property, placing them in `$HOME/.config/omarchy/plugins/`, and registering them in [`shell.json`](https://github.com/omacom/omarchy/blob/main/shell.json) via the `BarWidgetRegistry` system.**

Omarchy’s top-bar is built from extensible *bar widgets* (modules) that require no recompilation to customize. The shell uses a dynamic registry system defined in `shell/shell.qml` to map module IDs to QML component factories, allowing you to drop in custom code that persists across upgrades. This guide explains how to leverage the `BarWidgetRegistry` and [`shell.json`](https://github.com/omacom/omarchy/blob/main/shell.json) configuration to build and deploy custom bar modules.

## Understanding the Bar Widget Architecture

The Omarchy shell loads bar widgets through a three-tier system involving the registry, QML component definitions, and JSON manifest entries.

### The BarWidgetRegistry System

At startup, `shell/shell.qml` instantiates a central `BarWidgetRegistry`:

```qml
property BarWidgetRegistry barWidgetRegistry: BarWidgetRegistry { }

```

This registry maintains an internal map of **module IDs** (strings like `"omarchy.mywidget"`) to **QML component factories**. When `shell/plugins/bar/Bar.qml` renders the top bar, it iterates over registry entries and injects each widget into a `Repeater` that populates the layout regions (left, center, right). The registry’s `moduleWidgets(id)` helper returns instantiated components for any given `moduleName`.

### Widget Definition Requirements

Every bar module must be a QML file that exports a `moduleName` property:

```qml
property string moduleName: "omarchy.mywidget"

```

Built-in widgets reference `shell/plugins/bar/widgets/Workspaces.qml` as the canonical implementation. Custom widgets follow the same pattern but reside in user-space directories.

### Manifest Configuration

The [`shell.json`](https://github.com/omacom/omarchy/blob/main/shell.json) file (default location: [`config/omarchy/shell.json`](https://github.com/omacom/omarchy/blob/main/config/omarchy/shell.json)) stores the bar layout array. Each entry specifies:

- `id`: The module ID matching the QML `moduleName`
- `type`: Currently `"qml"` for all widgets
- `region`: `"left"`, `"center"`, or `"right"`
- `order`: Optional integer for placement priority within the region

Once you edit [`shell.json`](https://github.com/omacom/omarchy/blob/main/shell.json) for the first time, it becomes the **canonical** configuration, persisting your custom modules independently of Omarchy upgrades.

## Creating Your First Custom Bar Module

You can add a custom widget in three steps without modifying Omarchy core code.

### Step 1: Write the QML Component

Create a new directory for your plugin and add a `Widget.qml` file:

```qml
// File: ~/.config/omarchy/plugins/mywidget/Widget.qml
import QtQuick 2.15
import QtQuick.Controls 2.15

Item {
    // Unique identifier – must match shell.json entry
    property string moduleName: "omarchy.mywidget"

    Text {
        text: new Date().toLocaleTimeString()
        font.bold: true
        color: Theme.accent
        anchors.centerIn: parent
    }
}

```

The `moduleName` property is **required**—it tells `BarWidgetRegistry` how to route the component.

### Step 2: Register in shell.json

Add an entry to your user configuration at `~/.config/omarchy/shell.json` under the `bar.layout` array:

```json
{
  "id": "omarchy.mywidget",
  "type": "qml",
  "region": "right",
  "order": 5
}

```

The `region` controls horizontal placement, while `order` determines stacking priority within that region.

### Step 3: Install Using the CLI

Use Omarchy’s CLI to register the plugin and enable the widget:

```bash

# Create plugin directory and copy files

omarchy plugin add mywidget ~/.config/omarchy/plugins/mywidget

# Enable the widget in the bar (writes to shell.json)

omarchy bar put omarchy.mywidget '{"region":"right","order":5}'

```

The `omarchy bar put` command automatically updates [`shell.json`](https://github.com/omacom/omarchy/blob/main/shell.json), eliminating manual JSON editing.

## Advanced Widget Implementation

Beyond simple displays, you can build interactive controls using standard Qt Quick components.

### Building Interactive Controls

Here is a clickable widget that triggers notifications:

```qml
Item {
    property string moduleName: "omarchy.clicker"
    width: 80
    height: 30
    
    Rectangle {
        anchors.fill: parent
        color: "#334455"
        radius: 4
        
        Text {
            anchors.centerIn: parent
            text: "Click!"
            color: "white"
        }
        
        MouseArea {
            anchors.fill: parent
            onClicked: omarchyNotificationSend("Clicked!", "You pressed the custom bar widget")
        }
    }
}

```

This pattern works because `Bar.qml` injects the widget into the scene graph like any native component.

### Reference Implementation

Study `shell/plugins/bar/widgets/Workspaces.qml` in the Omarchy repository for a production-grade template. It demonstrates proper signal handling, theme integration, and layout constraints required for first-party widgets.

## Runtime Management and Persistence

The Omarchy shell provides CLI tools for modifying bar layouts without restarting.

### Modifying Layouts Dynamically

Use these commands to manage custom modules at runtime:

- `omarchy bar move <id> <region>` – Relocates a widget to a different bar region
- `omarchy bar put <id> <json>` – Adds or updates a widget’s configuration
- `omarchy plugin enable <name>` – Activates a plugin directory

Changes reflect immediately because `Bar.qml` binds to the registry’s model, and [`shell.json`](https://github.com/omacom/omarchy/blob/main/shell.json) persists your configuration.

### Upgrade Safety

Because custom widgets live in `$HOME/.config/omarchy/plugins/` and register via the user-specific [`shell.json`](https://github.com/omacom/omarchy/blob/main/shell.json), they survive Omarchy updates. The `BarWidgetRegistry` resolves module IDs at runtime, so core shell updates never overwrite your custom QML code.

## Summary

- **No recompilation required**: Drop QML files into `~/.config/omarchy/plugins/` and register them via [`shell.json`](https://github.com/omacom/omarchy/blob/main/shell.json).
- **Registry-based loading**: `shell/shell.qml` creates a `BarWidgetRegistry` that maps `moduleName` strings to component factories.
- **CLI integration**: Use `omarchy bar put` and `omarchy plugin add` to install widgets without manual JSON editing.
- **Persistent configuration**: Once modified, [`shell.json`](https://github.com/omacom/omarchy/blob/main/shell.json) becomes the canonical layout source, preserving custom modules across upgrades.
- **Reference code**: Study `shell/plugins/bar/widgets/Workspaces.qml` for implementation patterns.

## Frequently Asked Questions

### Do I need to rebuild Omarchy to add custom bar widgets?

No. Omarchy’s `BarWidgetRegistry` loads QML components dynamically from `shell/plugins/bar/widgets/` (built-in) or `$HOME/.config/omarchy/plugins/` (custom). Because the registry resolves `moduleName` properties at runtime, you can add, remove, or modify widgets without restarting the shell or recompiling source code.

### Where should I place third-party bar widget files?

Place custom QML files in `$HOME/.config/omarchy/plugins/<plugin-name>/Widget.qml`. The `omarchy plugin add` command copies directories into this location. Omarchy scans this path on startup alongside the built-in `shell/plugins/bar/widgets/` directory, treating user plugins as first-class modules.

### How does the shell determine which widgets appear in the bar?

`shell/plugins/bar/Bar.qml` reads the `bar.layout` array from [`shell.json`](https://github.com/omacom/omarchy/blob/main/shell.json). For each entry with `"type": "qml"`, it queries `BarWidgetRegistry.moduleWidgets(id)` to instantiate the corresponding QML component. Only widgets with matching `moduleName` properties and active manifest entries render in the UI.

### Can I change widget order without manually editing JSON?

Yes. Use the CLI command `omarchy bar move <id> <region>` to shift widgets between left, center, and right regions, or `omarchy bar put <id> '{"order":N}'` to adjust stacking priority. These commands modify [`shell.json`](https://github.com/omacom/omarchy/blob/main/shell.json) atomically and trigger immediate UI updates through the registry’s change notifications.