How the Active Bar Is Determined in Omarchy's shell.json

The active bar in Omarchy is determined at runtime by matching the currently focused monitor against the screen name stored in each BarModel instance, using the pickPanelSlot function to select the appropriate panel slot.

Omarchy’s desktop environment uses a dynamic panel system where the "active" bar—the one receiving input events and hosting open widgets—switches automatically based on monitor focus. This behavior is defined in the shell.json configuration but resolved through JavaScript logic in the Quickshell runtime. Understanding how the active bar is determined requires examining both the static configuration and the runtime selection algorithm.

The Configuration Foundation in shell.json

The static definition of Omarchy’s top-level panel resides in config/omarchy/shell.json under the bar object. This JSON structure specifies the layout, position, and widget IDs for the desktop bar, but it does not explicitly designate which monitor displays the active instance.

When Quickshell initializes, it reads this configuration and creates a BarModel instance for every connected monitor that has a bar configuration. Each instance registers its slots (widgets) with the panel system and stores the monitor’s identifier—referred to as the screenName—within the model for later comparison.

Runtime Bar Selection via BarModel.js

The core logic for determining which bar is active lives in shell/plugins/bar/BarModel.js. As implemented in the omacom/omarchy repository, the system maintains a list of candidate panel slots across all monitors and selects the active one based on current focus.

The selection process relies on two key inputs:

  • focusedScreen – The monitor identifier provided by Quickshell’s environment that indicates which screen currently has user focus
  • candidates – An array of panel slots, each tagged with its screenName and an opened status flag

The pickPanelSlot Algorithm

The pickPanelSlot(candidates, focusedScreen) function implements a three-tier fallback strategy to identify the active bar:

  1. Prefer opened slots – If any slot has its opened flag set to true, that slot takes priority regardless of focus
  2. Fallback to focused screen – If no slots are open, select the slot whose screenName matches focusedScreen
  3. Visibility check – Use pickDrawnSlot to ensure the selected slot is actually visible and has non-zero dimensions

When the user moves focus to a different monitor, the next invocation of pickPanelSlot automatically selects that monitor’s bar, seamlessly switching the active panel context.

Practical Implementation Example

The following code demonstrates how to determine and interact with the active bar programmatically:

// 1. Determine the focused screen (provided by Quickshell)
const focusedScreen = Quickshell.env("focusedScreen");

// 2. Build an array of candidate panel slots (one per monitor)
const candidates = [
  { slot: barModelA.slot, screenName: "DP-1", opened: false },
  { slot: barModelB.slot, screenName: "HDMI-1", opened: true },
  // …
];

// 3. Choose the active slot – the bar on the focused monitor wins
const activeSlot = pickPanelSlot(candidates, focusedScreen);

// 4. The activeSlot is now used for popup routing, panel toggles, etc.
if (activeSlot) {
  // e.g. open the power panel on the active bar
  activeSlot.slot.openPanel("omarchy.power");
}

In this example, even though barModelA might correspond to the primary monitor, barModelB becomes the active bar because its monitor has focus (or because it has an opened widget).

Key Files in the Active Bar System

Understanding the full implementation requires examining these specific source files:

Summary

  • The active bar is not statically assigned in shell.json but determined dynamically at runtime based on monitor focus.
  • BarModel.js creates a model instance per monitor, storing the screenName for comparison against the focused screen.
  • pickPanelSlot selects the active bar by preferring opened slots, then falling back to the slot matching focusedScreen, and finally verifying visibility via pickDrawnSlot.
  • When focus moves between monitors, the active bar switches automatically without requiring configuration changes.

Frequently Asked Questions

How does Omarchy handle the active bar on single-monitor setups?

On single-monitor setups, the logic remains identical but simplified. Since only one BarModel instance exists in the candidates array, pickPanelSlot returns that instance by default regardless of focus state. If no monitor reports focus (a rare edge case), the first available bar instance becomes the default active bar.

Can a widget force its bar to become active without changing monitor focus?

Yes. Widgets can influence the active bar selection through the opened flag. When a widget sets its slot's opened property to true, pickPanelSlot prioritizes that slot over others, even if the monitor does not currently have focus. This allows popups and system trays to maintain context on their original bar.

What happens if the focused screen does not have a bar configured?

If the currently focused monitor lacks a bar configuration in shell.json, no BarModel exists for that screen name. In this scenario, pickPanelSlot skips the focus-matching logic and falls back to selecting the first opened slot, or if none are open, the first drawn (visible) slot from any monitor that has a bar.

Where does the focusedScreen value originate?

The focusedScreen value originates from the Quickshell runtime environment, accessed via Quickshell.env("focusedScreen"). This environment variable is updated automatically by the compositor whenever the user shifts focus between monitors, triggering the bar selection logic to re-evaluate and potentially switch the active bar.

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 →