Skip to content

Getting Started

Requirements

  • Python ≥ 3.11
  • One of the supported Qt bindings: PySide6 or PyQt6

Installation

QtShadcn is published on PyPI. A Qt binding is intentionally not bundled; install the one your application already uses so your app controls the Qt runtime version.

pip install qtshadcn
pip install PySide6  # or PyQt6
uv add qtshadcn
uv add PySide6  # or PyQt6
# Clones the repo and installs all dev deps (PySide6, ruff, pytest, mkdocs…)
git clone https://github.com/BugCodeX/QtShadcn
cd QtShadcn
uv sync --extra dev

Minimal Setup

1. Create a theme file

Save this as my_theme.xml next to your script:

<theme>
  <light>
    <background>#ffffff</background>
    <foreground>#020617</foreground>
    <primary>#0f172a</primary>
    <primary_foreground>#f8fafc</primary_foreground>
    <secondary>#f1f5f9</secondary>
    <secondary_foreground>#0f172a</secondary_foreground>
    <accent>#f1f5f9</accent>
    <accent_foreground>#0f172a</accent_foreground>
    <muted>#f1f5f9</muted>
    <muted_foreground>#64748b</muted_foreground>
    <destructive>#ef4444</destructive>
    <destructive_foreground>#f8fafc</destructive_foreground>
    <border>#e2e8f0</border>
    <input>#e2e8f0</input>
    <ring>#0f172a</ring>
    <radius>8px</radius>
    <font_family>Open Sans</font_family>
    <spacing>4px</spacing>
    <card>#ffffff</card>
    <card_foreground>#020617</card_foreground>
    <popover>#ffffff</popover>
    <popover_foreground>#020617</popover_foreground>
  </light>
  <dark>
    <background>#020617</background>
    <foreground>#f8fafc</foreground>
    <primary>#f8fafc</primary>
    <primary_foreground>#0f172a</primary_foreground>
    <secondary>#1e293b</secondary>
    <secondary_foreground>#f8fafc</secondary_foreground>
    <accent>#1e293b</accent>
    <accent_foreground>#f8fafc</accent_foreground>
    <muted>#1e293b</muted>
    <muted_foreground>#94a3b8</muted_foreground>
    <destructive>#7f1d1d</destructive>
    <destructive_foreground>#f8fafc</destructive_foreground>
    <border>#1e293b</border>
    <input>#1e293b</input>
    <ring>#cbd5e1</ring>
    <radius>8px</radius>
    <font_family>Open Sans</font_family>
    <spacing>4px</spacing>
    <card>#020617</card>
    <card_foreground>#f8fafc</card_foreground>
    <popover>#020617</popover>
    <popover_foreground>#f8fafc</popover_foreground>
  </dark>
</theme>

2. Apply the theme

import sys
from PySide6 import QtWidgets
from qtshadcn import ThemeParseError, setTheme, setThemeMode, getTheme

app = QtWidgets.QApplication(sys.argv)

try:
    setThemeMode("auto", save=False)  # follows the OS — or use "light" / "dark"
    setTheme("my_theme.xml", save=False)
except ThemeParseError as e:
    print(f"Could not load theme: {e}")
    sys.exit(1)

tokens = getTheme()
print(f"Active primary color: {tokens.primary}")

btn = QtWidgets.QPushButton("Hello, QtShadcn!")
btn.show()
sys.exit(app.exec())

Using the Default Theme

QtShadcn ships with a default theme. Load it by calling setTheme with no argument, or simply query the active tokens after setting the mode:

from qtshadcn import getTheme, setThemeMode

setThemeMode("dark", save=False)
tokens = getTheme()

Using Bundled Fonts

QtShadcn includes Open Sans and Roboto under qtshadcn/resources/fonts/. To activate them, set font_family in your XML:

<font_family>Open Sans</font_family>

The fonts are registered automatically when the stylesheet is rendered.


Theme Mode Options

Value Behavior
"auto" Follows the OS light/dark preference (default)
"light" Always use the <light> palette
"dark" Always use the <dark> palette

setThemeMode accepts the string values "auto", "light", and "dark":

from qtshadcn import setTheme, setThemeMode

setThemeMode("dark", save=False)
setTheme("my_theme.xml", save=False)

Window-Scoped Theming

By default, QtShadcn applies the generated stylesheet to the entire application (QApplication.instance()). For applications with a single main window or when you want to style a specific window subtree independently, pass target to setThemeMode, setTheme, or setStyleSheet:

from PySide6 import QtWidgets
from qtshadcn import setTheme, setThemeMode

app = QtWidgets.QApplication([])
window = QtWidgets.QMainWindow()

# Scope the stylesheet to this window and its child dialogs
setThemeMode("dark", target=window, save=False)
setTheme("my_theme.xml", target=window, save=False)

window.show()
app.exec()

Window scoping speeds up theme switching in single-window applications by avoiding repolishing every widget across the entire process. Child dialogs (such as QColorDialog or QFileDialog parented to the window) inherit the window stylesheet, while independent sibling windows remain unstyled.


Supported Qt Bindings

QtShadcn supports two Qt bindings through a native shim:

  1. PySide6
  2. PyQt6

Choosing a binding

If only one supported binding is installed, the shim uses it automatically. If both are installed, PySide6 is preferred.

Import Qt classes from the binding you installed in your application code:

from PySide6 import QtWidgets

app = QtWidgets.QApplication([])

The public API remains the same regardless of which binding is active.