---
layout: "@layouts/ConfigLayout.astro"
title: "Introduction"
---

import Collapsible from "@components/Collapsible.astro";
import MD_Title from "@components/MD_Title.tsx"

# {frontmatter.title}

This page will walk you through the process of creating a simple bar/panel, and
introduce you to all the basic concepts involved.

There are many links to the [QML Overview](../qml-overview)
and [Type Reference](/docs/types) which you should follow if you don't
fully understand the concepts involved.

## <MD_Title titleVar={2} client:visible> Shell Files </MD_Title>

Every quickshell instance starts from a shell root file, conventionally named `shell.qml`.
The default path is `~/.config/quickshell/shell.qml`.
(where `~/.config` can be substituted with `$XDG_CONFIG_HOME` if present.)

Each shell file starts with the shell root object. Only one may exist per configuration.

```qml {filename="~/.config/quickshell/shell.qml"}
import Quickshell

@@Quickshell.ShellRoot {
  // ...
}
```

The shell root is not a visual element but instead contains all of the visual
and non visual objects in your shell. You can have multiple different shells
with shared components and different shell roots.

<Collapsible title="Shell search paths and manifests">
Quickshell can be launched with configurations in locations other than the default one.

The `-p` or `--path` option will launch the shell root at the given path.
It will also accept folders with a `shell.qml` file in them.
It can also be specified via the `QS_CONFIG_PATH` environment variable.

The `-c` or `--config` option will launch a configuration from the current manifest,
or if no manifest is specified, a subfolder of quickshell's base path.
It can also be specified via the `QS_CONFIG_NAME` environment variable.

The base path defaults to `~/.config/quickshell`, but can be changed using
the `QS_BASE_PATH` environment variable.

The `-m` or `--manifest` option specifies the quickshell manifest to read configs
from. When used with `-c`, the config will be chosen by name from the manifest.
It can also be specified via the `QS_MANIFEST` environment variable.

The manifest path defaults to `~/.config/quickshell/manifest.conf` and is a list
of `name = path` pairs where path can be relative or absolute.
Lines starting with `#` are comments.

```properties
# ~/.config/quickshell/manifest.conf
myconf1 = myconf
myconf2 = ./myconf
myconf3 = myconf/shell.nix
myconf4 = ~/.config/quickshell/myconf
```

You can use `quickshell --current` to print the current values of any of these
options and what set them.

</Collapsible>

## <MD_Title titleVar={2}> Creating Windows </MD_Title>

Quickshell has two main window types available,
[PanelWindow](/docs/types/quickshell/panelwindow) for bars and widgets, and
[FloatingWindow](/docs/types/quickshell/floatingwindow) for standard desktop windows.

We'll start with an example:

```qml
import Quickshell // for ShellRoot and PanelWindow
import QtQuick // for Text

@@Quickshell.ShellRoot {
  @@Quickshell.PanelWindow {
    anchors {
      top: true
      left: true
      right: true
    }

    height: 30

    @@QtQuick.Text {
      // center the bar in its parent component (the window)
      anchors.centerIn: parent

      text: "hello world"
    }
  }
}
```

The above example creates a bar/panel on your currently focused monitor with
a centered piece of [text](https://doc.qt.io/qt-6/qml-qtquick-text.html). It will also reserve space for itself on your monitor.

More information about available properties is available in the [type reference](/docs/types/quickshell/panelwindow).

## <MD_Title titleVar={2}> Running a process </MD_Title>

Now that we have a piece of text, what if it did something useful?
To start with lets make a clock. To get the time we'll use the `date` command.

We can use a [Process](/docs/types/quickshell.io/process) object to run commands
and return their results.

We'll listen to the @@Quickshell.Io.DataStreamParser.read(s) signal emitted by
@@Quickshell.Io.SplitParser using a
[signal handler](/docs/configuration/qml-overview/#signal-handlers)
to update the text on the clock.

> [!note/Note]
> Quickshell live-reloads your code. You can leave it open and edit the
> original file. The panel will reload when you save it.

```qml
import Quickshell
import Quickshell.Io // for Process
import QtQuick

@@Quickshell.ShellRoot {
  @@Quickshell.PanelWindow {
    anchors {
      top: true
      left: true
      right: true
    }

    height: 30

    @@QtQuick.Text {
      // give the text an ID we can refer to elsewhere in the file
      id: clock

      anchors.centerIn: parent

      // create a process management object
      @@Quickshell.Io.Process {
        // the command it will run, every argument is its own string
        command: ["date"]

        // run the command immediately
        running: true

        // process the stdout stream using a SplitParser
        // which returns chunks of output after a delimiter
        stdout: @@Quickshell.Io.SplitParser {
          // listen for the read signal, which returns the data that was read
          // from stdout, then write that data to the clock's text property
          onRead: data => clock.text = data
        }
      }
    }
  }
}
```

## <MD_Title titleVar={2}> Running code at an interval </MD_Title>

With the above example, your bar should now display the time, but it isn't updating!
Let's use a @@QtQml.Timer to fix that.

```qml
import Quickshell
import Quickshell.Io
import QtQuick

@@Quickshell.ShellRoot {
  @@Quickshell.PanelWindow {
    anchors {
      top: true
      left: true
      right: true
    }

    height: 30

    @@QtQuick.Text {
      id: clock
      anchors.centerIn: parent

      @@Quickshell.Io.Process {
        // give the process object an id so we can talk
        // about it from the timer
        id: dateProc

        command: ["date"]
        running: true

        stdout: @@Quickshell.Io.SplitParser {
          onRead: data => clock.text = data
        }
      }

      // use a timer to rerun the process at an interval
      @@QtQml.Timer {
        // 1000 milliseconds is 1 second
        interval: 1000

        // start the timer immediately
        running: true

        // run the timer again when it ends
        repeat: true

        // when the timer is triggered, set the running property of the
        // process to true, which reruns it if stopped.
        onTriggered: dateProc.running = true
      }
    }
  }
}
```

## <MD_Title titleVar={2}> Reusable components </MD_Title>

If you have multiple monitors you might have noticed that your bar
is only on one of them. If not, you'll still want to **follow this section
to make sure your bar doesn't disappear if your monitor disconnects**.

We can use a @@Quickshell.Variants object to create instances of _non widget items_.
(See @@QtQuick.Repeater for doing
something similar with visual items.)

The @@Quickshell.Variants type creates instances of a @@QtQml.Component based on
a data model you supply. (A component is a re-usable tree of objects.)

The most common use of @@Quickshell.Variants in a shell is to create instances of
a window (your bar) based on your monitor list (the data model).

@@Quickshell.Variants will inject the values in the data model into each new
component's `modelData` property, which means we can easily pass each screen
to its own component. (See @@Quickshell.QsWindow.screen.)

```qml
import Quickshell
import Quickshell.Io
import QtQuick

@@Quickshell.ShellRoot {
  @@Quickshell.Variants {
    model: Quickshell.screens;

    delegate: @@QtQml.Component {
      @@Quickshell.PanelWindow {
        // the screen from the screens list will be injected into this
        // property
        property var modelData

        // we can then set the window's screen to the injected property
        screen: modelData

        anchors {
          top: true
          left: true
          right: true
        }

        height: 30

        @@QtQuick.Text {
          id: clock
          anchors.centerIn: parent

          @@Quickshell.Io.Process {
            id: dateProc
            command: ["date"]
            running: true

            stdout: @@Quickshell.Io.SplitParser {
              onRead: data => clock.text = data
            }
          }

          @@QtQml.Timer {
            interval: 1000
            running: true
            repeat: true
            onTriggered: dateProc.running = true
          }
        }
      }
    }
  }
}
```

<span class="small">
  See also: [Property Bindings](/docs/configuration/qml-overview/#property-bindings),
  [Array.map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)
</span>

With this example, bars will be created and destroyed as you plug and unplug them,
due to the reactive nature of the
@@Quickshell.Quickshell.screens property.
(See: [Reactive Bindings](/docs/configuration/qml-overview/#reactive-bindings).)

Now there's an important problem you might have noticed: when the window
is created multiple times we also make a new Process and Timer. We can fix
this by moving the Process and Timer outside of the window.

> [!caution/Error]
> This code will not work correctly.

```qml
import Quickshell
import Quickshell.Io
import QtQuick

@@Quickshell.ShellRoot {
  @@Quickshell.Variants {
    model: Quickshell.screens

    delegate: @@QtQml.Component {
      @@Quickshell.PanelWindow {
        property var modelData
        screen: modelData

        anchors {
          top: true
          left: true
          right: true
        }

        height: 30

        @@QtQuick.Text {
          id: clock
          anchors.centerIn: parent
        }
      }
    }
  }

  @@Quickshell.Io.Process {
    id: dateProc
    command: ["date"]
    running: true

    stdout: @@Quickshell.Io.SplitParser {
      onRead: data => clock.text = data
    }
  }

  @@QtQml.Timer {
    interval: 1000
    running: true
    repeat: true
    onTriggered: dateProc.running = true
  }
}
```

However there is a problem with naively moving the Process and Timer
out of the component.
_What about the `clock` that the process references?_

If you run the above example you'll see something like this in the console every second:

```
file:///home/name/.config/quickshell/shell.qml:33: ReferenceError: clock is not defined
file:///home/name/.config/quickshell/shell.qml:33: ReferenceError: clock is not defined
file:///home/name/.config/quickshell/shell.qml:33: ReferenceError: clock is not defined
file:///home/name/.config/quickshell/shell.qml:33: ReferenceError: clock is not defined
file:///home/name/.config/quickshell/shell.qml:33: ReferenceError: clock is not defined
```

This is because the `clock` object, even though it has an ID, cannot be referenced
outside of its component. Remember, components can be created _any number of times_,
including zero, so `clock` may not exist or there may be more than one, meaning
there isn't an object to refer to from here.

We can fix it with a [Property Definition](/docs/configuration/qml-overview/#property-definitions).

We can define a property inside of the ShellRoot and reference it from the clock
text instead. Due to QML's [Reactive Bindings](/docs/configuration/qml-overview/#reactive-bindings),
the clock text will be updated when we update the property for every clock that
currently exists.

```qml
import Quickshell
import Quickshell.Io
import QtQuick

@@Quickshell.ShellRoot {
  id: root

  // add a property in the root
  property string time;

  @@Quickshell.Variants {
    model: Quickshell.screens

    delegate: @@QtQml.Component {
      @@Quickshell.PanelWindow {
        property var modelData
        screen: modelData

        anchors {
          top: true
          left: true
          right: true
        }

        height: 30

        @@QtQuick.Text {
          // remove the id as we don't need it anymore

          anchors.centerIn: parent

          // bind the text to the root's time property
          text: root.time
        }
      }
    }
  }

  @@Quickshell.Io.Process {
    id: dateProc
    command: ["date"]
    running: true

    stdout: @@Quickshell.Io.SplitParser {
      // update the property instead of the clock directly
      onRead: data => root.time = data
    }
  }

  @@QtQml.Timer {
    interval: 1000
    running: true
    repeat: true
    onTriggered: dateProc.running = true
  }
}
```

Now we've fixed the problem so there's nothing actually wrong with the
above code, but we can make it more concise:

1. `Component`s can be defined implicitly, meaning we can remove the
   component wrapping the window and place the window directly into the
   `delegate` property.
2. The @@Quickshell.Variants.delegate property is a
   [Default Property](/docs/configuration/qml-overview/#the-default-property),
   which means we can skip the `delegate:` part of the assignment.
   We're already using the default property of @@Quickshell.ShellRoot to store our
   Variants, Process, and Timer components among other things.
3. The ShellRoot doesn't actually need an `id` property to talk about
   the time property, as it is the outermost object in the file which
   has [special scoping rules](/docs/configuration/qml-overview/#property-access-scopes).

This is what our shell looks like with the above (optional) cleanup:

```qml
import Quickshell
import Quickshell.Io
import QtQuick

@@Quickshell.ShellRoot {
  property string time;

  @@Quickshell.Variants {
    model: Quickshell.screens

    @@Quickshell.PanelWindow {
      property var modelData
      screen: modelData

      anchors {
        top: true
        left: true
        right: true
      }

      height: 30

      @@QtQuick.Text {
        anchors.centerIn: parent

        // now just time instead of root.time
        text: time
      }
    }
  }

  @@Quickshell.Io.Process {
    id: dateProc
    command: ["date"]
    running: true

    stdout: @@Quickshell.Io.SplitParser {
      // now just time instead of root.time
      onRead: data => time = data
    }
  }

  @@QtQml.Timer {
    interval: 1000
    running: true
    repeat: true
    onTriggered: dateProc.running = true
  }
}
```

## <MD_Title titleVar={2}> Multiple files </MD_Title>

In an example as small as this, it isn't a problem, but as the shell
grows it might be preferable to separate it into multiple files.

To start with, let's move the entire bar into a new file.

```qml {filename="shell.qml"}
import Quickshell

@@Quickshell.ShellRoot {
  Bar {}
}
```

```qml {filename="Bar.qml"}
import Quickshell
import Quickshell.Io
import QtQuick

@@Quickshell.Scope {
  property string time;

  @@Quickshell.Variants {
    model: Quickshell.screens

    @@Quickshell.PanelWindow {
      property var modelData
      screen: modelData

      anchors {
        top: true
        left: true
        right: true
      }

      height: 30

      @@QtQuick.Text {
        anchors.centerIn: parent

        // now just time instead of root.time
        text: time
      }
    }
  }

  @@Quickshell.Io.Process {
    id: dateProc
    command: ["date"]
    running: true

    stdout: @@Quickshell.Io.SplitParser {
      // now just time instead of root.time
      onRead: data => time = data
    }
  }

  @@QtQml.Timer {
    interval: 1000
    running: true
    repeat: true
    onTriggered: dateProc.running = true
  }
}
```

<span class="small">See also: [Scope](/docs/types/Quickshell/Scope/)</span>

Any qml file that starts with an uppercase letter can be referenced this way.
We can bring in other folders as well using
[import statements](/docs/configuration/qml-overview/#explicit-imports).

Now what about breaking out the clock? This is a bit more complex because
the clock component in the bar, as well as the process and timer that
make up the actual clock, need to be dealt with.

To start with, we can move the clock widget to a new file. For now it's just a
single @@QtQuick.Text object but the same concepts apply regardless of complexity.

```qml {filename="ClockWidget.qml"}
import QtQuick

@@QtQuick.Text {
  // A property the creator of this type is required to set.
  // Note that we could just set `text` instead, but don't because your
  // clock probably will not be this simple.
  required property string time

  text: time
}
```

```qml {filename="Bar.qml"}
import Quickshell
import Quickshell.Io
import QtQuick

@@Quickshell.Scope {
  id: root
  property string time;

  @@Quickshell.Variants {
    model: Quickshell.screens

    @@Quickshell.PanelWindow {
      property var modelData
      screen: modelData

      anchors {
        top: true
        left: true
        right: true
      }

      height: 30

      // the ClockWidget type we just created
      ClockWidget {
        anchors.centerIn: parent
        // Warning: setting `time: time` will bind time to itself which is not what we want
        time: root.time
      }
    }
  }

  @@Quickshell.Io.Process {
    id: dateProc
    command: ["date"]
    running: true

    stdout: @@Quickshell.Io.SplitParser {
      onRead: data => time = data
    }
  }

  @@QtQml.Timer {
    interval: 1000
    running: true
    repeat: true
    onTriggered: dateProc.running = true
  }
}
```

While this example is larger than what we had before, we can now expand
on the clock widget without cluttering the bar file.

Let's deal with the clock's update logic now:

```qml {filename="Time.qml"}
import Quickshell
import Quickshell.Io
import QtQuick

@@Quickshell.Scope {
  property string time;

  @@Quickshell.Io.Process {
    id: dateProc
    command: ["date"]
    running: true

    stdout: @@Quickshell.Io.SplitParser {
      onRead: data => time = data
    }
  }

  @@QtQml.Timer {
    interval: 1000
    running: true
    repeat: true
    onTriggered: dateProc.running = true
  }
}
```

```qml {filename="Bar.qml"}
import Quickshell

@@Quickshell.Scope {
  // the Time type we just created
  Time { id: timeSource }

  @@Quickshell.Variants {
    model: Quickshell.screens

    @@Quickshell.PanelWindow {
      property var modelData
      screen: modelData

      anchors {
        top: true
        left: true
        right: true
      }

      height: 30

      ClockWidget {
        anchors.centerIn: parent
        // now using the time from timeSource
        time: timeSource.time
      }
    }
  }
}
```

## <MD_Title titleVar={2}> Singletons </MD_Title>

Now you might be thinking, why do we need the `Time` type in
our bar file, and the answer is we don't. We can make `Time`
a [Singleton](/docs/configuration/qml-overview/#singletons).

A singleton object has only one instance, and is accessible from
any scope.

```qml {filename="Time.qml"}
// with this line our type becomes a singleton
pragma Singleton

import Quickshell
import Quickshell.Io
import QtQuick

// your singletons should always have Singleton as the type
@@Quickshell.Singleton {
  property string time

  @@Quickshell.Io.Process {
    id: dateProc
    command: ["date"]
    running: true

    stdout: @@Quickshell.Io.SplitParser {
      onRead: data => time = data
    }
  }

  @@QtQml.Timer {
    interval: 1000
    running: true
    repeat: true
    onTriggered: dateProc.running = true
  }
}
```

```qml {filename="ClockWidget.qml"}
import QtQuick

@@QtQuick.Text {
  // we no longer need time as an input

  // directly access the time property from the Time singleton
  text: Time.time
}
```

```qml {filename="Bar.qml"}
import Quickshell

@@Quickshell.Scope {
  // no more time object

  @@Quickshell.Variants {
    model: Quickshell.screens

    @@Quickshell.PanelWindow {
      property var modelData
      screen: modelData

      anchors {
        top: true
        left: true
        right: true
      }

      height: 30

      ClockWidget {
        anchors.centerIn: parent

        // no more time binding
      }
    }
  }
}
```

## <MD_Title titleVar={2}> JavaScript APIs </MD_Title>

In addition to calling external processes, a [limited set of javascript interfaces] is available.
We can use this to improve our clock by using the [Date API] instead of calling `date`.

[limited set of javascript interfaces]: https://doc.qt.io/qt-6/qtqml-javascript-functionlist.html
[Date API]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date

```qml {filename="Time.qml"}
pragma Singleton

import Quickshell
import Quickshell.Io
import QtQuick

@@Quickshell.Singleton {
  property var date: new Date()
  property string time: date.toLocaleString(Qt.locale())

  @@QtQml.Timer {
    interval: 1000
    running: true
    repeat: true
    onTriggered: date = new Date()
  }
}
```
