# How the Color Singleton Works in Omarchy QML: A Deep Dive into Theme-Aware Colors

> Explore the Color singleton in Omarchy QML. Learn how this pragma Singleton centralizes reactive, theme-aware colors that automatically update with configuration changes.

- Repository: [Omacom/omarchy](https://github.com/omacom/omarchy)
- Tags: deep-dive
- Published: 2026-09-04

---

**The Color singleton is a `pragma Singleton` object that centralizes all color values in Omarchy QML, providing reactive, theme-aware colors that update automatically when configuration files change.**

The Omarchy window manager uses a sophisticated theming system where the **Color singleton** serves as the single source of truth for all UI colors. Located in `shell/Commons/Color.qml`, this singleton abstracts the complexity of theme parsing and provides a hierarchical, reactive color system that other QML components consume through simple property bindings.

## What Is the Color Singleton?

The **Color singleton** is a QML singleton type declared with `pragma Singleton` at the top of `shell/Commons/Color.qml`. Unlike regular QML objects, singletons exist as unique global instances that can be imported anywhere in the application without instantiation.

Other components access the singleton through the import statement:

```qml
import "Commons/Color.qml" as Color

```

This design pattern ensures that every widget references the same color values, maintaining visual consistency across the entire shell while enabling instant updates when the user switches themes or modifies configuration files.

## The Foundational Color Palette

At the core of the singleton lies a **foundational palette** defined on lines 19–23 of `shell/Commons/Color.qml`. These five properties establish the base color vocabulary:

- **foreground** – Primary text color
- **background** – Window and surface backgrounds  
- **accent** – Highlight and selection states
- **urgent** – Critical notifications and alerts
- **muted** – Secondary or disabled text

These properties initialize with fallback hex values ensuring the shell remains functional even without theme files. When the `colorsFile` loader completes (lines 24–30), the singleton populates these properties from the theme's [`colors.toml`](https://github.com/omacom/omarchy/blob/main/colors.toml) file, replacing the fallbacks with theme-specific values.

## Surface-Specific Color Objects

Beyond the foundational palette, the singleton exposes **surface-specific colors** as read-only `QtObject` instances. Each major UI surface receives its own dedicated object:

- `bar` – Top panel and status indicators
- `popup` – Dialog windows and overlays
- `tooltip` – Hover information panels
- `notifications` – Alert toasts
- `menu` – Context menus
- `polkit` – Authentication dialogs
- `lock` – Screen lock interface
- `image-picker` – File selection dialogs

For example, the bar surface begins at line 73 as a `QtObject` containing properties like `background`, `text`, and `border`. These properties do not store hardcoded values; instead, they bind to the foundational palette through helper functions that resolve color tokens dynamically.

## Helper Functions for Color Resolution

The singleton implements four specialized helper functions that transform theme tokens into actual color values:

### `pick(token, fallback)` (lines 30–34)

Returns a string value from the reactive `shellValues` dictionary or the provided fallback. This function serves as the primary lookup mechanism for arbitrary color keys defined in theme configurations.

### `pickAlpha(token)` (lines 35–41)

Extracts numeric alpha values from the shell configuration, clamping them between valid ranges using `Util.clampAlpha`. This ensures opacity values remain within 0.0–1.0 bounds before application.

### `flatColor(token, fallback)` (lines 43–65)

Resolves color tokens including role aliases (`foreground`, `accent`) and gradient definitions. This function handles the indirection where a theme might reference "accent" rather than a raw hex code, recursively resolving the actual color value.

### `composed(token, alphaToken, fallback, fallbackAlpha)` (lines 67–71)

Combines a base color with its alpha companion using `Util.alpha`, producing semi-transparent variants. This enables declarative definitions like `Color.composed("popup.overlay", "popup.overlay-alpha", Color.background, 0.6)` to generate overlays with variable opacity.

## Theme Data Flow and Reactive Updates

The singleton implements a four-stage pipeline that converts static TOML files into reactive QML properties:

1. **Loading** – `colorsFile` and `shellFile` loaders read [`colors.toml`](https://github.com/omacom/omarchy/blob/main/colors.toml) and [`shell.toml`](https://github.com/omacom/omarchy/blob/main/shell.toml) from the active theme directory (lines 24–38). Their `onLoaded` callbacks trigger `loadColors()` and `loadShell()` respectively.

2. **Parsing Colors** – The `loadColors()` function (lines 35–65) parses color definitions using regex patterns to extract values for `foreground`, `background`, `accent`, `muted`, `color0` through `color15`, and other palette entries.

3. **Parsing Shell Values** – `parseShell()` (lines 73–99) transforms the raw [`shell.toml`](https://github.com/omacom/omarchy/blob/main/shell.toml) structure into a flat dictionary mapping "section.key" strings to their values, enabling dot-notation lookups like `bar.background`.

4. **Merging** – Theme-provided values (`themeShellValues`) merge with user overrides (`userShellValues`) on lines 101–108, producing the reactive `shellValues` property. Because QML bindings automatically track property assignments, all surface colors re-evaluate instantly when `shellValues` changes.

## Runtime Theme Reloading

A critical feature of the Omarchy Color singleton is **hot-reloading** of user customizations without restarting the shell. The singleton maintains a `userShellFile` watcher (lines 39–53) that monitors `~/.config/omarchy/shell.toml` for modifications.

When the file changes:
- The `reload()` method triggers
- `userShellValues` reparses from disk
- The merge logic recomputes `shellValues`
- All QML bindings automatically refresh

This architecture enables users to tweak colors in real-time using a text editor, seeing immediate results across the entire desktop environment.

## Practical Usage Examples

### Basic Surface Colors

Reference predefined surface colors directly from the singleton:

```qml
import "Commons/Color.qml" as Color

Rectangle {
    color: Color.bar.background
    width: 200; height: 40
    
    Text {
        text: "Omarchy"
        color: Color.bar.text
        anchors.centerIn: parent
    }
}

```

### Semi-Transparent Compositions

Create overlays using the composition helper:

```qml
Item {
    width: 100; height: 100
    
    Rectangle {
        anchors.fill: parent
        color: Color.composed(
            "popup.overlay", 
            "popup.overlay-alpha",
            Color.background, 
            0.6
        )
    }
}

```

### Custom Theme Tokens

Access arbitrary values from [`shell.toml`](https://github.com/omacom/omarchy/blob/main/shell.toml) with fallback protection:

```qml
Item {
    property color highlight: Color.pick("custom.highlight", "#ff00ff")
    // Changing ~/.config/omarchy/shell.toml updates this instantly:
    // [custom]
    // highlight = "#00ff00"
}

```

## Summary

- The **Color singleton** in `shell/Commons/Color.qml` is a `pragma Singleton` type that provides global access to theme-aware colors without multiple instantiation.
- **Foundational colors** (`foreground`, `background`, `accent`, `urgent`, `muted`) initialize with fallbacks on lines 19–23, then populate from [`colors.toml`](https://github.com/omacom/omarchy/blob/main/colors.toml) via the `colorsFile` loader.
- **Surface objects** like `bar`, `popup`, and `tooltip` expose read-only color properties derived through helper functions including `pick()`, `pickAlpha()`, `flatColor()`, and `composed()`.
- The **reactive pipeline** loads theme files, parses TOML structures, and merges user overrides into `shellValues`, causing automatic UI updates when configurations change.
- **Runtime reloading** watches `~/.config/omarchy/shell.toml` (lines 39–53), enabling instant theme customization without shell restarts.

## Frequently Asked Questions

### How do I import the Color singleton in my Omarchy widget?

Import the singleton using `import "Commons/Color.qml" as Color` at the top of your QML file. Because it is registered as a singleton with `pragma Singleton`, you do not create an instance with `Color {}`; instead, access properties directly through the type name like `Color.bar.background` or `Color.accent`.

### What happens if a color is missing from the theme configuration?

The singleton provides fallback values for all foundational colors (lines 19–23) and the `pick()` function accepts a fallback parameter. If a requested token does not exist in the merged `shellValues` dictionary, the system returns the fallback hex code specified in the function call or the default palette values.

### Can I modify colors without restarting Omarchy?

Yes. The singleton monitors `~/.config/omarchy/shell.toml` through the `userShellFile` watcher (lines 39–53). When you save changes to this file, the singleton automatically reparses the configuration, remerges the values, and updates all bound properties throughout the UI instantly.

### Where are the color values actually stored?

Color values exist in three tiers: the **theme files** (`themes/*/colors.toml` and `themes/*/shell.toml`), the **user override file** (`~/.config/omarchy/shell.toml`), and the **reactive `shellValues` property** within the singleton. The singleton merges these sources at runtime, with user values taking precedence over theme defaults.