|
|
Log in / Subscribe / Register

A look at the Quickshell desktop-component toolkit

August 20, 2026

This article was contributed by Tyler Langlois

Quickshell is a toolkit for building desktop components, such as toolbars or menus. It uses QML, which is a declarative language for designing GUI applications. Quickshell helps developers create graphical tools for common desktop use cases with a focus on ease of development. It offers a convenient method for writing user interfaces and has been adopted by a number of projects, such as caelestia-shell and DankMaterialShell, that provide desktop environments for minimal window managers like Sway and niri.

A high-level toolkit

Quickshell arose from a need for easier methods to build interfaces for desktop components, such as a system tray or management interface for audio devices. Other toolkits can achieve similar results but require a significant up-front investment to gain familiarity with their development environments and libraries. As we will see below, it can be used to easily create utilities, such as a desktop launcher or toolbar, that are useful for a desktop environment.

The project's creator and lead developer "outfoxxed" tried existing solutions like Elkowar's Wacky Widgets (eww), another desktop widget system, but ran into challenges that prompted them to look elsewhere.

Their preference for Qt over GTK also led outfoxxed toward a custom solution that eventually became Quickshell. "Some time in December 2023 I was testing Qt Quick for viability in another project that never happened, and I noticed that it was really approachable since the language has features like automatic reactive bindings". That refers to property binding, which allows QML to propagate changing values through parts of its structure. For example, the text of a button does not need special treatment to reflect updates if its string value incorporates another value that changes in response to an event being triggered. The bindings QML establishes between properties handles updates by tracking dependencies that change over time and updating them as needed.

Qt and GTK are popular for writing desktop components on Linux. However, using them means writing lower-level code and involves compilation steps that incur delays during iterative development. Quickshell bridges the gap between desktop APIs and the Qt graphical toolkit. It also adds the ability to iterate rapidly when building desktop interfaces. With just Quickshell installed, users can create their own graphical interfaces with any of the types listed in its documentation, such as PopupWindow or SystemTray, available for use directly in QML documents, which are stored as .qml files. Although it's well-suited for minimalist desktops, it is also useful for creating desktop widgets and other utilities to be used with more full-fledged desktop environments like GNOME and KDE Plasma as well.

Additionally, while APIs for services like Pipewire are generally available on most Linux distributions, each API requires familiarity with those individual services to properly use them. Types like Pipewire provided by Quickshell make the process of working with these services much easier.

Quickshell had its first release, version 0.1, in June 2024. The most recent, version 0.3, was released in June 2026 with new API features for networking, polkit integration, as well as many other enhancements and bug fixes. It is packaged for many Linux distributions, though it is not available in Debian 13, but is in testing. Debian packages are also available on the Open Build Service. It is provided under the LGPLv3 and hosted on on GitHub, which is the primary channel for user contributions and issue tracking, with a mirror hosted on an independent Forgejo server.

Outfoxxed is the primary committer and reviewer, responsible for the bulk of development. However, community contributions like wired-networking support have helped to significantly improve the project. The project's contribution policy neither bans nor endorses the use of LLM-assisted coding but does require that changes are owned by human developers and forbids the use of completely automated tooling to contribute code.

A shell ecosystem

Minimalist compositors and window managers intentionally provide little more than the core capabilities needed to display and manage windows; users are left to their own devices to choose other components to build the desktop they want. Projects such as Waybar (which provides standalone toolbars) or Rofi (an application launcher) can close the gap. There are many other similar projects that provide specific features to window managers or compositors, but assembling a complete desktop environment from small applications takes some effort.

Popular Quickshell-based projects, such as caelestia-shell and DankMaterialShell, offer a middle ground. They do not provide feature parity with desktop environments, such as GNOME and Plasma, but they provide many of the features users might want from a desktop when using bare-bones compositors such as Sway and niri.

Desktop shells built with Quickshell are usually configurable with user-friendly graphical interfaces rather than text-based configuration files. Interfaces built with Quickshell can be styled via QML types that add effects like animations and styles. The DankMaterialShell theme gallery has many examples of how one might style Quickshell. DankMaterialShell also has support for plugins, which lets users add third-party widgets (or create their own).

Some of Quickshell's features depend upon the window manager or compositor in use. For example, using background transparency blurring in Quickshell while on Wayland requires a compositor that supports the ext-background-effect Wayland protocol. Support for modern Wayland compositors is usually consistent across projects that rely on foundational libraries like wlroots (Sway) and Smithay (such as niri and COSMIC). In the case of niri, for example, support for ext-background-effect was added on the 26.04 release.

A trove of types

QML is used to express the structure and function of interface elements that are managed by the Qt framework. Quickshell is configured via QML files that declare objects derived from the upstream QML types. These types are high-level abstractions that can be instantiated to create elements like buttons or windows.

The syntax of QML can be thought of as a layer of abstraction above using Qt directly. Elements are declared rather than constructed in an imperative style. For example, while Qt widgets like layouts and labels might be created like this in Python:

    from PyQt6.QtWidgets import (QGridLayout, QLabel)
    layout = QGridLayout()
    label = QLabel("Using Qt 6 in Python.")
    layout.addWidget(label)

The equivalent QML instead creates the desired structure declaratively:

    import QtQuick.Controls
    import QtQuick.Layouts
    GridLayout {
        Label {
            text: "Using Qt 6 with QML."
        }
    }

To support interactive elements like buttons, events are bound to scripts written in JavaScript that are compiled internally by the QML engine.

Quickshell extends the available QtQuick types with its own types that provide additional capabilities. (QtQuick is the standard library of types available for use with QML.) Many of the bundled Quickshell types serve as abstractions over common APIs and other desktop interfaces.

For example, Quickshell provides the Process type that is generally useful for running shell commands and capturing their output. However, the UPower type grants more convenient access to host information: rather than parsing files in /sys/class/power_supply to discover a battery's charge level, GUI elements can rely on the UPowerDevice.percentage property for a device.

Quickshell types like Bluetooth, Networking, and Sockets let developers work with high-level properties to easily make use of system state. For example, text content or the icon path of an object can react when the connected property of a Network type changes.

There are some tradeoffs in using Quickshell versus building natively with Qt or GTK. While QML may be embedded in different languages like Python or C++, QML scripting is limited to JavaScript (although developers can extend QML via some techniques with C++). GTK or Qt may be better suited for building interfaces with specific languages, or with more complex backend logic, where a greater degree of control is available.

QML and declarative interfaces

To illustrate a concrete example of a GUI built with Quickshell, the following minimal QML imports types from the QtQuick library and creates a Text object with its text property set to a static string value:

    import QtQuick
    
    Text {
        text: "Hello from Quickshell!"
    }

Quickshell will use the QML file ~/.config/quickshell/shell.qml by default when running the quickshell command, or specific QML files may be passed to quickshell with the -p/--path flag. Changes to the text property of the Text object will be reflected immediately when saving the shell.qml file. The resulting interface shown here is running on a default niri desktop configuration.

Simple Quickshell example with a Text object.

That is probably not very useful, by itself, however. The next example shows how to change shell.qml to bind events to JavaScript expressions and make an interface interactive. It builds a FloatingWindow with a stacked row layout comprised of a Text object and a Button. Clicking the button increments the customData variable tracking the number of clicks and updates the text property in response to the changing value.

    import QtQuick
    import QtQuick.Controls
    import QtQuick.Layouts
    import Quickshell
    
    FloatingWindow {
        property var customData: 0
        ColumnLayout {
            Text {
                text: `Clicks: ${customData}`
            }
            Button {
                text: "Increment"
                onClicked: customData += 1
            }
        }
    }

This example uses several types from the QtQuick imports in addition to the FloatingWindow type from the Quickshell namespace. Writing to the file is sufficient to prompt Quickshell to rebuild the interface and create a functional interactive window. Clicking on the Button element labeled "Increment" will dynamically update the Text object in the Quickshell window.

An interactive Quickshell window example with text and a button.

As a final demonstration of Quickshell's capabilities, the following QML uses DesktopEntries to retrieve Freedesktop.org desktop application specification files and construct a scrollable grid of buttons to launch corresponding entries, closing the launcher after selection.

The FloatingWindow also uses several Quickshell helper functions like Quickshell.iconPath to resolve icon paths and Quickshell.execDetached to run the desktop entry's executable in the background. The .execDetached function expects a list of arguments, passed here as an array with the desktop entry's execString as the singular element.

The GridView type works by accepting a collection of items passed to its model property (in this case, an array called DesktopEntries.applications) and instantiating a new object for every element in that collection. The delegate property controls how to consume each element of the collection: in this example, a new RoundButton object is created with the modelData variable available to retrieve other values like modelData.icon for the icon path of the desktop entry. The addition of a ToolTip provides application names as hover text when the mouse cursor is placed over the icon. Calls to functions like Qt.quit use the always-imported Qt namespace.

    import QtQuick
    import QtQuick.Controls
    import Quickshell
    import Quickshell.Widgets
    
    FloatingWindow  {
        title: "LWN Launcher"
    
        ScrollView {
            anchors.fill: parent
    
            GridView {
                id: grid
                cellWidth: 48
                cellHeight: 48
    
                model: DesktopEntries.applications
    
                delegate: RoundButton {
                    radius: 0
                    implicitWidth: grid.cellWidth
                    implicitHeight: grid.cellWidth
    
                    hoverEnabled: true
                    ToolTip.text: modelData.name
                    ToolTip.visible: hovered
    
                    contentItem: IconImage {
                        source: Quickshell.iconPath(modelData.icon)
                    }
    
                    onClicked: {
                        Quickshell.execDetached([modelData.execString]);
                        Qt.quit()
                    }
                }
            }
        }
    }

The end result is a simple grid of icon buttons that displays all installed desktop applications with Freedesktop entries. Importantly, the Quickshell widget is portable: most desktop applications install Freedesktop.org entries, and there are no window manager or compositor-specific elements to the QML. The overall result should be similar whether started from niri, Sway, Plasma, or any other standard desktop environment. There are countless ways to further customize this GUI or enrich it with additional features.

A Quickshell launcher demonstration displaying a grid of icons.

Conclusion

My own experience with Quickshell has been in combination with niri on NixOS. Although I originally wrote my own toolbars, launcher, and other elements, DankMaterialShell has now become my default desktop shell. Quickshell remains useful to write focused utilities that require GUIs like menus for scripts or silly proof-of-concepts. However, DankMaterialShell offers a degree of polish that might be hard to otherwise achieve on my own. As with many young projects, the main drawback tends to be the rapid pace of changes that occasionally necessitate manual intervention when plugins break or versions drift, but anecdotally, stability seems to be improving rapidly.

Both Quickshell and its related desktop-shell projects boast particularly well-written and comprehensive documentation for further reading. In addition to the documentation already linked, Quickshell provides an introduction to writing QML. The DankMaterialShell documentation includes useful guides for authoring plugins as well as how to manage and update an existing installation.

Quickshell is relatively new on the Linux desktop scene, but its quick adoption seems to be making an impact across Linux distributions and desktop environments.


Index entries for this article
GuestArticlesLanglois, Tyler


to post comments

Forgotten lessons of the past

Posted Aug 20, 2026 19:45 UTC (Thu) by dskoll (subscriber, #1630) [Link] (17 responses)

It's almost as if someone has reinvented Tcl/Tk, albeit with a more modern look.

Forgotten lessons of the past

Posted Aug 20, 2026 20:24 UTC (Thu) by jzb (editor, #7867) [Link] (14 responses)

Almost. Has anyone created a whole desktop shell with Tcl/Tk? That would be ... interesting.

Forgotten lessons of the past

Posted Aug 20, 2026 21:17 UTC (Thu) by dskoll (subscriber, #1630) [Link] (5 responses)

Hmm, that I don't know. I assume it could be done in principle. The examples in the article, though, could all definitely be done easily with Tcl/Tk.

Forgotten lessons of the past

Posted Aug 20, 2026 21:59 UTC (Thu) by bauermann (guest, #37575) [Link] (4 responses)

For interesting values of "easily".

I've been using Tcl on and off for 20 years when working with DejaGnu testcases, and it always struck me as an odd language, difficult to get used to. In the beginning I tried to learn it a bit but never felt comfortable with it and after a while I decided to just imitate what other testcases do.

I only started understanding it a bit better a few years ago, after I decided to learn Scheme. Then it dawned on me that Tcl is a mixture between Bourne shell and Lisp. Or at least it makes more sense to me when I look at it that way.

I guess it was a valid research direction in the 80s, but in today's programming languages landscape it doesn't make a lot of sense, IMHO. Of course, mostly because of the Bourne shell influence, not the Lisp part.

Forgotten lessons of the past

Posted Aug 20, 2026 22:39 UTC (Thu) by anselm (subscriber, #2796) [Link] (3 responses)

I guess it was a valid research direction in the 80s, but in today's programming languages landscape it doesn't make a lot of sense, IMHO. Of course, mostly because of the Bourne shell influence, not the Lisp part.

Tcl/Tk is great – the implementation is very well-engineered and easy to understand, and it works fine for what it does. After more than 30 years it is still second to none in the GUI-programming-made-easy department. Tcl/Tk had things like reasonable Unicode and threading support way before most other mainstream programming languages, and provides interesting features such as “safe interpreters” or the Tk canvas and text widgets, which are very powerful indeed. Tcl is also designed to be extended with C code, and the Tcl-to-C extension interface is very easy to understand (certainly much more so than, e.g., the Python-to-C extension interface) and fun to work with.

Tcl/Tk's most obvious problem in 2026 is probably that Tk doesn't support Wayland, but that is apparently being worked on, so I wouldn't declare it dead just yet.

Forgotten lessons of the past

Posted Aug 23, 2026 14:38 UTC (Sun) by marcH (subscriber, #57642) [Link] (2 responses)

I don't know Tk but the main problem with Tcl is roughly the same as with shell scripts: it's very loosely typed and there is practically no static check. The LISP-inspired syntax is odd and not very attractive but you can get used to it quickly.

Python is not perfect but I don't see why any new, non-Tk project would prefer Tcl over Python. Also because the "ecosystem" of the latter is at least one order of magnitude bigger and more active. I bet Tcl had tremendous value at the time. Today, not so much.

But again: I don't know Tk. Maybe the tkinter indirection sucks (like most indirections) and maybe Tk is what gives Tcl a lot of value even today.

Forgotten lessons of the past

Posted Aug 23, 2026 15:20 UTC (Sun) by dskoll (subscriber, #1630) [Link] (1 responses)

Tcl was never designed to be used for large programs; it was assumed that most of the core would be written in C or C++ and Tcl would just be an extension language. But it turned out that people did write large programs in Tcl anyway.

I hate Python, myself, but this is a personal thing. 🙂 So I've never written anything big in Python and haven't looked at TkInter.

Tk is superb from a programmer's point of view. In particular, its various geometry managers make it very easy to create GUIs that respond well to being resized. And yes, I think Tk is what gives Tcl most of its value. The only major public non-Tk project that uses Tcl extensively that I'm aware of is expect.

A lot of proprietary EDA (Electronic Design Automation) tools use Tcl as an extension language; that's its niche just as games seem to be Lua's niche.

But bringing this discussion so it's somewhat relevant to the parent article: I would much rather have a full-fledged scripting language for creating GUIs than a configuration language (QML) with hacks for executing other programs. I suspect that the Quickshell designers will slowly realize this and that their configuration language will morph into a Turing-complete scripting language, when they could have saved themselves a lot of time just by embedding Tcl or Lua or whatever.

Forgotten lessons of the past

Posted Aug 23, 2026 19:40 UTC (Sun) by anselm (subscriber, #2796) [Link]

I suspect that the Quickshell designers will slowly realize this and that their configuration language will morph into a Turing-complete scripting language, when they could have saved themselves a lot of time just by embedding Tcl or Lua or whatever.

The original plan behind Tcl was to offer it as a standardised extension language for applications which would otherwise eventually roll their own (incomplete, bug-ridden, …) extension languages. This is why it is so ridiculously easy to interface Tcl with C code – the idea is that all the heavy lifting would be done in C, with the application making its functionality available as Tcl commands, and you would use Tcl code to tie it all together (and then later when Tk came out, use Tk to put a GUI on top of it). Remember that those were the days of OSF/Motif and the like, where a “Hello world” type X11 program would come to about two pages' worth of #include directives and boilerplate code while in Tcl/Tk, “Hello world” takes up all of three lines. Back in the early 1990s Tk was a real game changer, not just because it turned GUI programming for X11 into something that normal people could do, but also because it included nifty stuff like the send command, which lets a Tcl/Tk-enabled program send commands to (and receive results from) other Tcl/Tk-enabled programs on the same X11 display.

Later on in its career Tcl acquired the ability to load C libraries dynamically, and that enticed people to write applications by extending wish (the Tcl/Tk “shell”) with application-specific C code, rather than link the Tcl libraries into their own pre-existing applications (written in C). This was something that required some care because Tcl wasn't really meant for big programs, but you could do amazing things. One of my pet projects at the time was a DVI previewer for TeX output (back when PDF wasn't really a thing yet), where the DVI rendering code was implemented as a type of Tk “canvas object”, i.e., you could mix TeX output with other canvas stuff (including interactive canvas stuff, JPEG graphics, you name it), render several pages of TeX output on the same canvas, etc. Since the DVI rendering code was written in C it was very fast, and in fact there was no perceived difference in speed between my program and xdvi, including features like the magnifying glass (which in the case of my program would be funneled through Tcl/Tk for the event handling). That project kinda petered out when everyone moved over to PDF but it was great fun at the time.

Forgotten lessons of the past

Posted Aug 21, 2026 12:07 UTC (Fri) by smoogen (subscriber, #97) [Link] (3 responses)

The original Red Hat Linux Desktops before GNOME were pretty much all TCL/Tk desktops sitting on top of FVWM2. It was a pile of 'code' written I think in part by Donnie Barnes and many others dropping tidbits here and there to try and get something working. One of the main problems is that a lot of underlying technology which got added to make 'desktops' usable in the form of background busses to communicate between widgets and applications were either not written yet or in infancy. Adding them into TCL/Tk was not easy since it could break where TCL/Tk was in heavy use (aka Unix workstations versus Linux). The original KDE desktop and GNOME desktops added many technologies which we now take for granted that the QuickShell or other items take advantage of.

I don't know what the current state of TCL/Tk is but if they have been ported to it, then a modern desktop could be possible also.

Forgotten lessons of the past

Posted Aug 21, 2026 15:47 UTC (Fri) by dskoll (subscriber, #1630) [Link] (2 responses)

Tcl/Tk is a bit behind in terms of dbus support and such. Version 9.0 does have a built-in way to do desktop notifications and supports the system tray, though.

Long before any desktops had bus-like communication, Tk had the very powerful send command that could let you evaluate a Tcl script in the process of another graphical application. There's a demo script that ships with Tk called rmt that lets you attach to any running Tcl/Tk app and type commands that are evaluated in its interpreter. It's a very powerful debugging tool.

Forgotten lessons of the past

Posted Aug 22, 2026 1:59 UTC (Sat) by csigler (subscriber, #1224) [Link] (1 responses)

They really named the script 'rmt'? There is (was) a UNIX 'rmt' command to operate remote tape drives. I haven't used it in 30+ years. But yet another namespace clash...

Forgotten lessons of the past

Posted Aug 22, 2026 2:09 UTC (Sat) by dskoll (subscriber, #1630) [Link]

Yes, they really did name it rmt. And I am absolutely shocked to discover that the original tape-related rmt is installed on my Debian 13 system! Apparently the Debian tar package ships with a program called rmt-tar and it's the version of rmt selected by Debian's alternatives mechanism on my system.

I remember using the related mt command. I bought some sort of weird cartridge tape drive as a backup for my Linux computer in 1996 or 1997. I don't even remember the brand name, though.

Forgotten lessons of the past

Posted Aug 21, 2026 18:32 UTC (Fri) by lollipopman (subscriber, #120613) [Link]

This person seems to be trying to make it happen still, TeaOS

Forgotten lessons of the past

Posted Aug 22, 2026 0:18 UTC (Sat) by ccchips (subscriber, #3222) [Link] (2 responses)

TKDesk? Just came to me and I don't have time to look around for it right now, but I wanted to mention it.

Forgotten lessons of the past

Posted Aug 22, 2026 0:20 UTC (Sat) by ccchips (subscriber, #3222) [Link]

It's still there in the Mint softwre manager list.

Forgotten lessons of the past

Posted Aug 22, 2026 2:12 UTC (Sat) by dskoll (subscriber, #1630) [Link]

I downloaded it to take a look. Sadly does not compile against modern Tcl/Tk. Considering the last relase was in 2004, I'm not surprised that 22 years of bitrot would make it fail to compile.

Forgotten lessons of the past

Posted Aug 24, 2026 10:00 UTC (Mon) by eru (subscriber, #2753) [Link]

For me it looked rather like the Swing Builder of Groovy ( https://groovy-lang.org/dsls.html#swingbuilder).
Declarative GUI builders have probably been reinvented many times.

It's a popularity thing

Posted Aug 24, 2026 13:54 UTC (Mon) by jpeisach (subscriber, #181966) [Link]

Some software happens to take off and become more popular (via word of mouth or it being a dependency of other projects). As someone of the younger generation (I am 18), Tcl/Tk is something nobody has heard of. I had to relearn what Tcl was for this comment. Last time I touched it was making a LFS build.

Anyways, probably because of the "modernity" factor, and how much "cool, modern, beautiful animations" have taken off, especially amongst younger users, that's probably why they just found Quickshell and not something else.

Also, Quickshell is more specifically targeted to desktops. Tcl/Tk is more general (you can see on the website)

So while it is definitely aesthetics and modernity, the truth is, nobody knows what Tcl/Tk was, and it's just not as specific and guided towards the goal of Quickshell. And because of the popularity aspects, this will be forgotten...

I do wonder, how this will impact distribution packaging. If you're a source based distro, no problem, but for distros that package on stability, having to keep track of so many different DEs that are similar may be difficult because of a "niche" user base.


Copyright © 2026, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds