What Kinds of Plugins Can a Quickshell Plugin Declare? A Complete Guide to Quickshell Plugin Types
Quickshell plugins declare a kinds array in their manifest.json file to specify their type, with six supported values—bar, bar-widget, panel, overlay, menu, and service—that determine how the shell loads the plugin and where it appears in the UI.
Quickshell, the extensible shell framework from the basecamp/omarchy repository, uses a declarative manifest system where each plugin must announce its capabilities through the kinds field. The PluginRegistry.validateManifest function validates this array during installation, and the shell core uses these entries to route the plugin to the correct UI container or background service loader.
The Six Quickshell Plugin Kinds
Every Quickshell plugin must declare at least one kind from the supported set. Each kind triggers distinct loading behavior in shell/shell.qml and determines whether the plugin renders as a visual component or runs as a background process.
bar
The bar kind designates a complete bar layout option. When a plugin declares this kind, the shell treats it as a candidate for the active bar configuration.
According to the source code in shell/services/PluginRegistry.qml (lines 28–34), the shell compares the plugin ID against config.bar.id to determine whether this bar plugin should be instantiated. Only one bar plugin can be active at a time, and the selection is controlled by the user's configuration.
bar-widget
The bar-widget kind indicates a component that lives inside the bar’s layout. Unlike the bar kind, which replaces the entire bar, widgets occupy specific sections.
As implemented in shell/shell.qml (lines 659–675), the shell inserts enabled bar widgets into config.bar.layout.left, config.bar.layout.center, or config.bar.layout.right based on the manifest’s defaultSection property or explicit placement configuration. The registry validates these entries before the shell creates their QML components.
panel
The panel kind represents a traditional floating window or dock-style interface. Panels are added to the top-level config.plugins[] array and loaded through the generic panel loader.
The implementation in shell/shell.qml (lines 598–603) shows that panels are instantiated as distinct windows that users can position and manage independently of the main bar.
overlay
The overlay kind creates fullscreen or semi-transparent UI layers that appear above other windows. Overlays share the same config.plugins[] storage as panels but are distinguished by their kind during initialization.
The shell handles overlays in shell/shell.qml (lines 589–595), where it checks for the overlay kind to apply appropriate window flags and stacking behavior, ensuring the UI appears above normal application windows.
menu
The menu kind defines launcher-style interfaces, such as dmenu or application menu implementations. Like panels and overlays, menus are stored in config.plugins[].
The loading logic in shell/shell.qml (lines 589–595) processes menus alongside overlays, though they are typically triggered by specific keybindings or bar buttons rather than appearing as persistent windows.
service
The service kind declares a background process that provides functionality without UI components. Services do not appear in the bar or plugins list.
As noted in shell/shell.qml (lines 265–291), the shell loads services through a dedicated service loader that instantiates the QML component but never adds it to a visual layout. These plugins run silently to provide APIs, data sources, or system integration for other UI components.
How PluginRegistry Validates Plugin Kinds
The PluginRegistry.validateManifest function in shell/services/PluginRegistry.qml (lines 64–66) enforces that every manifest contains a valid kinds array. The registry ensures that each entry matches one of the six supported types and that the manifest includes corresponding entryPoints for each declared kind.
If validation passes, the registry stores the plugin metadata and exposes helper methods like entryPointUrl(manifest, kind), which the shell uses to resolve the correct QML file for each plugin type.
Implementing Each Kind in Your Manifest
Declaring Multiple Kinds
Plugins can combine kinds when they provide both UI and background functionality. A manifest declaring a panel and a service resembles:
{
"schemaVersion": 1,
"id": "example.panel-service",
"name": "Example Panel + Service",
"version": "1.0.0",
"kinds": ["panel", "service"],
"entryPoints": {
"panel": "Panel.qml",
"service": "Service.qml"
}
}
Declaring Bar Widgets
Bar widgets require placement hints and a single entry point:
{
"schemaVersion": 1,
"id": "example.clock-widget",
"name": "Clock Widget",
"version": "1.0.0",
"kinds": ["bar-widget"],
"entryPoints": {
"bar-widget": "BarWidget.qml"
},
"barWidget": {
"defaultSection": "right"
}
}
Loading Services Programmatically
When the shell instantiates services, it checks the kinds array before creating the component:
// From shell/shell.qml – generic service loader
if (Array.isArray(manifest.kinds) && manifest.kinds.indexOf("service") !== -1) {
var url = pluginRegistry.entryPointUrl(manifest, "service")
// Create and start the service component
}
Inserting Bar Widgets into the Layout
The shell dynamically constructs the bar layout by splicing enabled widgets into the configuration:
// From shell/shell.qml – bar widget placement logic
if (isBarWidget && !location.found) {
var section = defaultBarWidgetSection(manifest)
var target = barTarget(config, placement || {}, section)
config.bar.layout[target.section].splice(target.index, 0, { id: key })
}
Summary
- Six distinct kinds define Quickshell plugin capabilities:
bar,bar-widget,panel,overlay,menu, andservice. PluginRegistry.validateManifestinshell/services/PluginRegistry.qmlenforces valid kind declarations during plugin installation.- Bar plugins compete for the single active bar slot via
config.bar.idcomparison. - Bar widgets inject into specific layout sections (left, center, right) of the active bar.
- Panels, overlays, and menus populate the
config.plugins[]array but receive different window treatments based on their kind. - Services run headless through a dedicated loader and never appear in the visual hierarchy.
Frequently Asked Questions
Can a single Quickshell plugin declare multiple kinds?
Yes. A plugin can declare multiple kinds in its manifest.json array, such as ["panel", "service"] to provide both a UI panel and a background service. The shell loads each kind independently using the corresponding entry point defined in the entryPoints object.
How does the shell decide which bar plugin to activate?
The shell compares the plugin ID against config.bar.id as implemented in shell/services/PluginRegistry.qml (lines 28–34). Only the plugin whose ID matches the configuration value becomes the active bar; other bar kind plugins remain dormant.
What is the difference between panel and overlay kinds?
Both store in config.plugins[], but the shell applies distinct window management in shell/shell.qml (lines 589–603). Panels typically appear as persistent dock windows, while overlays receive window flags that keep them above other applications, making them suitable for fullscreen launchers or system dashboards.
Do service plugins require entry points?
Yes. Even though services lack UI, they must specify a QML file in entryPoints.service. The shell loads this component via pluginRegistry.entryPointUrl() and instantiates it without adding it to any visual layout, as handled in shell/shell.qml (lines 265–291).
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 →