# How to Configure a Custom QML Widget for the Bar in Omarchy

> Learn to configure a custom QML widget for the Omarchy bar. Implement a QML Item, declare a plugin manifest, and use the omarchy bar put command for seamless integration.

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

---

**To configure a custom QML widget for the bar in Omarchy, declare a plugin manifest with `"kinds": ["bar-widget"]`, implement a QML `Item` that accepts the injected `bar`, `moduleName`, and `settings` properties, and place it using the `omarchy bar put` command.**

Omarchy’s desktop shell renders its status bar through **Quickshell**, loading modular widgets dynamically at runtime. When you configure a custom QML widget for the bar in Omarchy, you create a plugin that the `BarWidgetRegistry` (defined in `shell/shell.qml`) summons into the active bar layout. This guide covers the exact manifest format, QML implementation requirements, and placement workflows derived from the Omarchy source code.

## Understanding the Bar Widget Architecture

Omarchy manages bar widgets through two primary registry components that handle discovery and placement persistence.

**BarWidgetRegistry** (`shell/shell.qml`, lines 19-24) maintains a live registry of all enabled bar widgets, exposing the `summonBarWidget(id)` method that the active bar uses to instantiate widgets. When a widget is summoned, the runtime injects three critical properties into your QML root `Item`:

- **`bar`**: Provides access to styling tokens (`foreground`, `background`, `urgent`) and helper methods like `run(cmd)`
- **`moduleName`**: The unique identifier string from the manifest
- **`settings`**: A JavaScript object containing user-defined configuration values

**PluginRegistry** (`shell/services/PluginRegistry.qml`, lines 455-475) handles the IPC commands that persist widget placement in `~/.config/omarchy/shell.json`. This service implements `putBarWidget`, `moveBarWidget`, and `setBarWidget`, allowing runtime configuration without manual file editing.

## Step 1: Create the Plugin Manifest

Every custom widget begins with a [`manifest.json`](https://github.com/basecamp/omarchy/blob/main/manifest.json) file that declares the plugin type and entry point. The manifest must specify `"kinds": ["bar-widget"]` and map the `entryPoints.barWidget` key to your QML file.

Create the following structure in either a standalone git repository or inside `~/.config/omarchy/plugins/<your-id>/`:

```json
{
  "schemaVersion": 1,
  "id": "my.org.gpu-widget",
  "name": "GPU Meter",
  "version": "0.1.0",
  "author": "Your Name",
  "description": "Shows GPU usage on the bar",
  "kinds": ["bar-widget"],
  "entryPoints": { "barWidget": "Widget.qml" }
}

```

The `id` field must be globally unique (reverse-DNS notation recommended). The `entryPoints.barWidget` value is a relative path from the manifest directory to your QML implementation file.

## Step 2: Implement the QML Widget

The QML implementation file receives the three injected properties mentioned above and must be placed at the path specified in your manifest. Here is a complete implementation that displays GPU utilization using the `bar.run()` helper:

```qml
Item {
  // Injected by the runtime
  property var bar
  property string moduleName
  property var settings

  // Internal state
  property int usage: 0

  Text {
    id: label
    color: bar.foreground
    text: "GPU: " + usage + "%"
    anchors.centerIn: parent
  }

  function updateUsage() {
    bar.run("nvidia-smi --query-gpu=utilization.gpu --format=csv,noheader")
      .then(function(out) {
        usage = parseInt(out.trim())
      })
      .catch(function(err) { 
        console.warn(moduleName, "error:", err) 
      })
  }

  Timer {
    interval: settings.refreshInterval || 5000
    running: true
    repeat: true
    onTriggered: updateUsage()
  }

  Component.onCompleted: updateUsage()
}

```

The `bar` object exposes the shell’s styling palette and the `run(cmd)` method, which returns a Promise resolving to the command’s stdout. According to the documentation in [`docs/omarchy-shell.md`](https://github.com/basecamp/omarchy/blob/main/docs/omarchy-shell.md) (lines 91-100), you can access additional bar properties like `bar.height` and `bar.scale` to adapt your widget dimensions.

## Step 3: Enable and Place the Widget

After creating the manifest and QML file, register the widget with Omarchy’s plugin system and add it to the bar layout.

Enable the plugin:

```bash
omarchy plugin add https://github.com/yourname/omarchy-gpu-widget.git
omarchy plugin enable my.org.gpu-widget

```

Place the widget in the desired bar section:

```bash

# Add to the right side of the bar

omarchy bar put my.org.gpu-widget --section right

```

Adjust positioning later using the move command:

```bash
omarchy bar move my.org.gpu-widget --section left --index 1

```

These commands update `~/.config/omarchy/shell.json` immediately, and the `BarWidgetRegistry` reloads the layout without requiring a full session restart.

## Configuring Widget Settings at Runtime

You can store configuration data via the `setBarWidget` IPC command and retrieve it through the injected `settings` property.

Set a custom value:

```bash
omarchy bar set my.org.gpu-widget refreshInterval 10000

```

Access the value in your QML:

```qml
property int refreshInterval: settings.refreshInterval || 5000

```

The `settings` object persists in [`shell.json`](https://github.com/basecamp/omarchy/blob/main/shell.json) alongside the widget’s placement metadata, managed by the `PluginRegistry` service.

## Summary

- **Manifest declaration**: Create a [`manifest.json`](https://github.com/basecamp/omarchy/blob/main/manifest.json) with `"kinds": ["bar-widget"]` and an `entryPoints.barWidget` key pointing to your QML file.
- **Runtime properties**: Your QML root item receives `bar`, `moduleName`, and `settings` automatically from the `BarWidgetRegistry` in `shell/shell.qml`.
- **Shell integration**: Use `omarchy plugin enable <id>` to register the widget, then `omarchy bar put <id> --section <left|center|right>` to place it.
- **Dynamic configuration**: Store user preferences via `omarchy bar set` and access them through the `settings` property without restarting the shell.

## Frequently Asked Questions

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

Omarchy injects three properties into every bar widget’s root QML `Item`: `bar` (providing styling tokens and the `run()` method), `moduleName` (the widget’s unique identifier), and `settings` (user-defined configuration values). These are provided by the `BarWidgetRegistry` when it summons the widget into the active bar.

### Where does Omarchy store the position of custom bar widgets?

Widget placement is persisted in `~/.config/omarchy/shell.json` by the `PluginRegistry` service (`shell/services/PluginRegistry.qml`, lines 455-475). You can modify this file directly or use the `omarchy bar put` and `omarchy bar move` commands to update positions programmatically.

### Can I execute shell commands from within a QML bar widget?

Yes. Use the `bar.run(cmd)` method, which returns a JavaScript Promise that resolves with the command’s stdout string. This allows you to poll system status, read files, or interact with external utilities directly from your QML logic.

### How do I update a widget's settings without restarting Omarchy?

Use the CLI command `omarchy bar set <widget-id> <key> <value>`. This updates the `settings` object in [`shell.json`](https://github.com/basecamp/omarchy/blob/main/shell.json) immediately. Your QML code should bind to the `settings` property or watch for changes using property observers to react to configuration updates in real time.