# How to Create a Custom Omarchy Bar Widget: A Step-by-Step Guide

> Learn to create a custom Omarchy bar widget with this step-by-step guide. Build a QML component and JSON manifest, then enable the plugin to personalize your Omarchy experience.

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

---

**Creating a custom Omarchy bar widget requires building a QML visual component and a JSON manifest file in the `shell/plugins/bar/widgets/` directory, then enabling the plugin via the command line.**

Omarchy’s desktop shell uses a modular plugin architecture where the top bar renders **bar-widget** plugins. Each widget is a self-contained unit consisting of a QML visual item and a metadata manifest. When the shell starts, it scans `shell/plugins/bar/widgets/`, registers discovered widgets in the bar widget registry, and positions them according to `~/.config/omarchy/bar/layout.json`.

## Understanding the Bar Widget Architecture

Omarchy bar widgets follow a strict two-file pattern. Every widget lives in its own subdirectory under `shell/plugins/bar/widgets/` and contains:

- **A QML Item** – The visual component rendered inside one of the bar’s three sections (`left`, `center`, or `right`).
- **A manifest (`*.manifest.json`)** – Describes the widget’s ID, kind, entry point, and optional configuration schema to the Omarchy plugin system.

At runtime, the shell injects several properties into the QML root item: `shell` (the running Quickshell instance), `manifest` (the widget’s manifest JSON), and `omarchyPath` (the Omarchy installation directory). These allow the widget to interact with the bar and other services while maintaining security boundaries.

## Step-by-Step: Create a Custom Omarchy Bar Widget

### Create the Plugin Directory

Create a dedicated folder for your widget to keep it isolated and discoverable by the loader:

```bash
mkdir -p shell/plugins/bar/widgets/com.example.mywidget

```

Third-party widgets should use a unique namespace (e.g., `com.example.*`) to avoid collisions with first-party widgets that use the `omarchy.*` prefix.

### Write the QML Component

Create a QML file that extends `Item` (or any visual element). The bar automatically injects runtime helpers at the root level.

```qml
import QtQuick 2.15
import QtQuick.Layouts 1.15

Item {
    id: root
    
    // Injected properties provided by Omarchy:
    //   root.shell – the running Quickshell instance
    //   root.manifest – the widget’s manifest JSON
    //   root.omarchyPath – path to the Omarchy installation

    width: implicitWidth
    height: parent.height

    Rectangle {
        anchors.fill: parent
        color: "#2e3440"
        border.color: "#81a1c1"
        radius: 4

        Text {
            anchors.centerIn: parent
            text: "My Widget"
            color: "#eceff4"
            font.bold: true
        }
    }

    Component.onCompleted: {
        console.log("MyWidget loaded, id:", root.manifest.id)
    }
}

```

Reference the **KeyboardLayout.qml** implementation in `shell/plugins/bar/widgets/KeyboardLayout.qml` for a production example that exposes `target.hostWidget` and handles bar-widget lifecycle events.

### Define the Manifest File

Create a [`MyWidget.manifest.json`](https://github.com/omacom/omarchy/blob/main/MyWidget.manifest.json) file alongside your QML file. This tells Omarchy that the plugin provides a bar widget and where to find it.

```json
{
  "id": "com.example.mywidget",
  "kinds": ["bar-widget"],
  "firstParty": false,
  "entryPoints": {
    "barWidget": "MyWidget.qml"
  },
  "defaultSection": "right"
}

```

Key fields:
- **kinds**: Must include `"bar-widget"` to register in the bar widget registry.
- **entryPoints.barWidget**: Path to the QML file relative to the plugin directory.
- **defaultSection**: Optional. Defaults to `center` if omitted; use `"left"` or `"right"` to control initial placement.

### Configure Settings Schema (Optional)

If your widget requires user-configurable options, add a `configSchema` property to the manifest. This enables `omarchy plugin configure <id>` and native UI controls in the Settings menu.

```json
{
  "id": "com.example.mywidget",
  "kinds": ["bar-widget"],
  "entryPoints": {
    "barWidget": "MyWidget.qml"
  },
  "defaultSection": "right",
  "configSchema": {
    "title": "My Widget Settings",
    "type": "object",
    "properties": {
      "color": {
        "type": "string",
        "default": "#2e3440",
        "description": "Background color of the widget"
      }
    }
  }
}

```

### Enable and Register the Widget

Enable the plugin using the Omarchy CLI to add it to the bar layout:

```bash
omarchy plugin enable com.example.mywidget

```

Alternatively, you can manually edit `~/.config/omarchy/bar/layout.json` to adjust the widget’s position or section assignment.

### Test and Reload

Run the test shell or reload the bar to see live changes:

```bash
./test/shell

# or

omarchy bar reload

```

This validates that the widget loads without QML errors and respects the bar’s section constraints.

## Key Conventions and Security

**Widget Isolation**: Third-party widgets receive a *facade* that limits access to only their own service and the bar-widget API. This preserves security boundaries described in the **omarchy-shell** documentation, preventing unauthorized access to system internals.

**Data Models**: For complex widgets that manage lists or tray items, create a separate JavaScript model file. See [`shell/plugins/bar/widgets/TrayModel.js`](https://github.com/omacom/omarchy/blob/main/shell/plugins/bar/widgets/TrayModel.js) for an example of helper models that separate data logic from presentation, used by the Tray widget in `shell/plugins/bar/widgets/Tray.qml`.

**Naming Standards**: Always use a reverse-DNS namespace for third-party widgets (e.g., `com.example.mywidget`) to prevent namespace collisions with official `omarchy.*` widgets.

## Summary

- **Custom Omarchy bar widgets** consist of a QML visual item and a `*.manifest.json` file stored in `shell/plugins/bar/widgets/<namespace>/`.
- The **manifest** must specify `"kinds": ["bar-widget"]` and an `entryPoints.barWidget` path to register with the shell.
- **Injected properties** (`shell`, `manifest`, `omarchyPath`) provide runtime context without requiring hardcoded paths.
- **Enable widgets** via `omarchy plugin enable <id>` and reload the bar with `omarchy bar reload`.
- Study reference implementations like `shell/plugins/bar/widgets/KeyboardLayout.qml` and [`shell/plugins/bar/widgets/KeyboardLayout.manifest.json`](https://github.com/omacom/omarchy/blob/main/shell/plugins/bar/widgets/KeyboardLayout.manifest.json) for production-ready patterns.

## Frequently Asked Questions

### Where do I place custom bar widget files in Omarchy?

Create a new directory under `shell/plugins/bar/widgets/` using a reverse-DNS namespace (e.g., `com.example.mywidget/`). Place your QML file and manifest JSON inside this folder. The shell scans this directory on startup to populate the bar widget registry.

### What properties does Omarchy inject into QML bar widgets?

The shell automatically injects three properties at the root of your QML Item: `shell` (the Quickshell instance), `manifest` (your widget’s parsed manifest JSON), and `omarchyPath` (absolute path to the Omarchy installation). These allow your widget to query system state and render dynamic content without hardcoding paths.

### How do I change the default section of my bar widget?

Add `"defaultSection": "left"` (or `"right"`) to your manifest JSON. If omitted, the widget defaults to the `center` section. Users can override this later by editing `~/.config/omarchy/bar/layout.json` after enabling the plugin.

### What is the difference between first-party and third-party Omarchy widgets?

First-party widgets use the `omarchy.*` namespace (e.g., `omarchy.clock`) and have broader system access. Third-party widgets must use a unique namespace (e.g., `com.example.*`) and run inside a restricted facade that limits API access to the bar-widget interface, ensuring system security.