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

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:

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.

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 file alongside your QML file. This tells Omarchy that the plugin provides a bar widget and where to find it.

{
  "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.

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

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:

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

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →