How the Color Singleton Works in Omarchy QML: A Deep Dive into Theme-Aware Colors
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:
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 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 indicatorspopup– Dialog windows and overlaystooltip– Hover information panelsnotifications– Alert toastsmenu– Context menuspolkit– Authentication dialogslock– Screen lock interfaceimage-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:
-
Loading –
colorsFileandshellFileloaders readcolors.tomlandshell.tomlfrom the active theme directory (lines 24–38). TheironLoadedcallbacks triggerloadColors()andloadShell()respectively. -
Parsing Colors – The
loadColors()function (lines 35–65) parses color definitions using regex patterns to extract values forforeground,background,accent,muted,color0throughcolor15, and other palette entries. -
Parsing Shell Values –
parseShell()(lines 73–99) transforms the rawshell.tomlstructure into a flat dictionary mapping "section.key" strings to their values, enabling dot-notation lookups likebar.background. -
Merging – Theme-provided values (
themeShellValues) merge with user overrides (userShellValues) on lines 101–108, producing the reactiveshellValuesproperty. Because QML bindings automatically track property assignments, all surface colors re-evaluate instantly whenshellValueschanges.
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 userShellValuesreparses 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:
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:
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 with fallback protection:
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.qmlis apragma Singletontype 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 fromcolors.tomlvia thecolorsFileloader. - Surface objects like
bar,popup, andtooltipexpose read-only color properties derived through helper functions includingpick(),pickAlpha(),flatColor(), andcomposed(). - 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.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →