FluentPySide
fluentpyside packages the FluentWinUI3 Qt Quick Controls style so any Qt / PySide6 application can add the FluentWinUI3 theme easily. The goal is to make it simple to enable the Fluent theme without bundling the full PySide6 runtime into your application. For minimal, bloat-free builds prefer installing PySide6-Essentials on the target system rather than packaging compiled plugin binaries inside this package.
⚠️ IMPORTANT — Read this before using
This library is a QML visual theme only. It styles Qt Quick Controls 2 components (Button, TextField, CheckBox, etc.) to look like Windows 11's Fluent Design. It does NOT provide:
- A Python widget library (it does NOT touch
QtWidgets— noQPushButton,QLabel, etc.)- Custom QML components — you use the standard Qt Quick Controls 2 API, this library just changes how they look
For colors and design tokens, use the
Fluentsingleton (available after callingfluentpyside.apply()):Rectangle { color: Fluent.cardBackground radius: Fluent.radiusMedium Label { text: "Hello" color: Fluent.textPrimary font.pixelSize: Fluent.fontBodySize font.family: Fluent.fontFamily } }
Quick Start
pip install PySide6-Essentials # recommended — provides the runtime plugins
pip install fluentpyside
import fluentpyside
fluentpyside.apply()
That's it. apply() registers the FluentWinUI3 QML import path and sets the QtQuickControls2 style to FluentWinUI3. After that, any standard Qt Quick Controls 2 component in your QML will be rendered with the Fluent theme automatically.
How it works
You write standard QML using the normal Qt Quick Controls 2 imports. The fluentpyside.apply() call sets the style, so every component automatically gets the Fluent look — you don't import anything special, you don't reference any theme object, you just write normal QML.
# main.py
from PySide6.QtGui import QGuiApplication
from PySide6.QtQml import QQmlApplicationEngine
import fluentpyside
app = QGuiApplication([])
engine = QQmlApplicationEngine()
# ONE line — this is all you need
fluentpyside.apply()
engine.load("main.qml")
app.exec()
// main.qml
// NOTE: Only standard Qt imports — NO Fluent-specific import needed
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
ApplicationWindow {
visible: true
width: 400
height: 300
title: "FluentWinUI3 Demo"
ColumnLayout {
anchors.fill: parent
anchors.margins: 16
spacing: 12
Label {
text: "FluentWinUI3 Theme"
font.pixelSize: 20
font.bold: true
}
TextField {
placeholderText: "Type something..."
Layout.fillWidth: true
}
Button {
text: "Click me"
onClicked: console.log("Button clicked!")
}
CheckBox {
text: "Enable feature"
}
Switch {
text: "Dark mode toggle"
}
ProgressBar {
value: 0.6
Layout.fillWidth: true
}
ComboBox {
model: ["Option 1", "Option 2", "Option 3"]
Layout.fillWidth: true
}
Item { Layout.fillHeight: true }
}
}
Available styled components
These standard Qt Quick Controls 2 components get Fluent styling automatically when fluentpyside.apply() is called:
| Component | Notes |
|---|---|
ApplicationWindow |
Main window container |
Button |
Standard push button |
RoundButton |
Circular/pill-shaped button |
DelayButton |
Button that activates after holding |
ToolButton |
Toolbar button |
TextField |
Single-line text input |
TextArea |
Multi-line text input |
SearchField |
Text input with search icon (Qt 6.10+) |
SpinBox |
Numeric input with up/down arrows |
ComboBox |
Dropdown selector |
CheckBox |
Checkbox with label |
CheckDelegate |
Checkbox in a list item |
RadioButton |
Radio button with label |
RadioDelegate |
Radio button in a list item |
Switch |
Toggle switch |
SwitchDelegate |
Toggle switch in a list item |
Slider |
Horizontal slider |
RangeSlider |
Two-handle slider |
ProgressBar |
Linear progress indicator |
BusyIndicator |
Spinning loading indicator |
PageIndicator |
Dot-style page indicator |
GroupBox |
Labeled container frame |
Frame |
Container frame |
ScrollView |
Scrollable area (falls back to system) |
TabBar / TabButton |
Tab navigation |
ToolBar |
Toolbar container |
ToolSeparator |
Separator for toolbars |
MenuBar / MenuBarItem |
Top menu bar |
Menu / MenuItem / MenuSeparator |
Dropdown menus |
Dialog / DialogButtonBox |
Modal dialogs |
Popup |
Generic popup container |
ToolTip |
Hover tooltip |
ItemDelegate |
Clickable list item |
SwipeDelegate |
Swipeable list item |
Calendar |
Date picker with month navigation |
Dial |
Rotary/knob control (custom Fluent design) |
Drawer |
Sliding side panel (left/right/bottom, modal) |
Label |
Text label with Fluent typography |
Pane |
Background container with Fluent styling |
ScrollView |
Scrollable area with Fluent scrollbars |
SplitView |
Resizable split layout with styled divider |
StackView |
Navigation stack with slide transitions |
SwipeView |
Swipeable page container |
Tumbler |
Wheel/drum picker (3D effect) |
TreeView |
Expandable tree view with chevron indicators |
That's 52 styled components covering the full Qt Quick Controls 2 API. All components automatically switch between light and dark mode.
Gallery Demo
A comprehensive gallery showcasing every control is included. Run it with:
cd examples
python run_gallery.py
Fluent Design Tokens
After calling fluentpyside.apply(), a Fluent singleton is available in your QML with WinUI 3 design tokens. All colors automatically switch between light and dark mode based on the system preference (Fluent.isDark).
Example usage
import QtQuick
import QtQuick.Controls
ApplicationWindow {
visible: true; width: 600; height: 400
Rectangle {
anchors.fill: parent
color: Fluent.background
ColumnLayout {
anchors.centerIn: parent
Label {
text: "Welcome"
color: Fluent.textPrimary
font.pixelSize: Fluent.fontTitleSize
font.family: Fluent.fontFamily
}
Button {
text: "Accent Button"
Layout.alignment: Qt.AlignHCenter
}
Rectangle {
width: 200; height: 4
radius: Fluent.radiusSmall
color: Fluent.accent
Layout.alignment: Qt.AlignHCenter
}
}
}
}
Available properties
Surface Colors
| Property | Light | Dark |
|---|---|---|
Fluent.background |
#f3f3f3 |
#202020 |
Fluent.backgroundSecondary |
#e5e5e5 |
#1c1c1c |
Fluent.backgroundTertiary |
#f9f9f9 |
#282828 |
Fluent.cardBackground |
#ffffff |
#2d2d2d |
Fluent.cardBackgroundSecondary |
#f6f6f6 |
#383838 |
Fluent.popupBackground |
#ffffff |
#2d2d2d |
Fluent.layerBackground |
#e8e8e8 |
#2c2c2c |
Fluent.layerAltBackground |
#f6f6f6 |
#383838 |
Text Colors
| Property | Light | Dark |
|---|---|---|
Fluent.textPrimary |
#1a1a1a |
#ffffff |
Fluent.textSecondary |
#616161 |
#9d9d9d |
Fluent.textTertiary |
#8a8a8a |
#7a7a7a |
Fluent.textDisabled |
#a0a0a0 |
#5d5d5d |
Fluent.textOnAccent |
#ffffff |
#003d7a |
Accent Colors
| Property | Light | Dark |
|---|---|---|
Fluent.accent |
#005fb8 |
#60cdff |
Fluent.accentHover |
#004c95 |
#7dd6ff |
Fluent.accentPressed |
#003d7a |
#005a9e |
Fluent.accentSelected |
#c7e0f4 |
#003d7a |
Fluent.accentDisabled |
#a0a0a0 |
#3d7a9e |
Fluent.accentFocusOuter |
#005fb8 |
#60cdff |
Control Colors
| Property | Light | Dark |
|---|---|---|
Fluent.controlBackground |
#ffffff |
#3d3d3d |
Fluent.controlBackgroundHover |
#f0f0f0 |
#484848 |
Fluent.controlBackgroundPressed |
#e5e5e5 |
#3d3d3d |
Fluent.controlBackgroundDisabled |
#f9f9f9 |
#282828 |
Fluent.controlStrongBackground |
#005fb8 |
#60cdff |
Fluent.controlStrongForeground |
#ffffff |
#003d7a |
Fluent.controlAltBackground |
#f6f6f6 |
#383838 |
Fluent.controlAltBackgroundTransparentHover |
#00000005 |
#ffffff0a |
Fluent.controlAltBackgroundTransparentPressed |
#0000000f |
#ffffff14 |
Input / Text Field Colors
| Property | Light | Dark |
|---|---|---|
Fluent.inputBackground |
#ffffff |
#2d2d2d |
Fluent.inputBackgroundHover |
#f0f0f0 |
#383838 |
Fluent.inputBorder |
#9d9d9d |
#5d5d5d |
Fluent.inputBorderHover |
#7a7a7a |
#7a7a7a |
Fluent.inputBorderFocus |
#005fb8 |
#60cdff |
Fluent.inputPlaceholderForeground |
#8a8a8a |
#7a7a7a |
Fluent.inputForeground |
#1a1a1a |
#ffffff |
Border / Divider
| Property | Light | Dark |
|---|---|---|
Fluent.border |
#d1d1d1 |
#3d3d3d |
Fluent.borderStrong |
#9d9d9d |
#5d5d5d |
Fluent.borderDisabled |
#e5e5e5 |
#2d2d2d |
Fluent.divider |
#d1d1d1 |
#3d3d3d |
Fluent.dividerStrong |
#9d9d9d |
#5d5d5d |
Status Colors
| Property | Light | Dark |
|---|---|---|
Fluent.success |
#0f7b0f |
#6ccb5f |
Fluent.caution |
#9d5d00 |
#fcb900 |
Fluent.warning |
#ff8c00 |
#ffb900 |
Fluent.critical |
#c42b1c |
#ff99a4 |
Fluent.informational |
#005fb8 |
#60cdff |
Typography
| Property | Value |
|---|---|
Fluent.fontFamily |
"Segoe UI Variable" |
Fluent.fontCaptionSize |
12 |
Fluent.fontBodySize |
14 |
Fluent.fontBodyStrongSize |
14 |
Fluent.fontBodyLargeSize |
16 |
Fluent.fontSubtitleSize |
20 |
Fluent.fontTitleSize |
28 |
Fluent.fontTitleLargeSize |
40 |
Fluent.fontDisplaySize |
68 |
Spacing
| Property | Value |
|---|---|
Fluent.spacingXXS |
2 |
Fluent.spacingXS |
4 |
Fluent.spacingS |
8 |
Fluent.spacingM |
12 |
Fluent.spacingL |
16 |
Fluent.spacingXL |
20 |
Fluent.spacingXXL |
24 |
Radius
| Property | Value |
|---|---|
Fluent.radiusSmall |
4 |
Fluent.radiusMedium |
8 |
Fluent.radiusLarge |
12 |
Fluent.radiusXLarge |
16 |
Fluent.radiusCircle |
9999 |
Requirements
- Python 3.8+
- PySide6-Essentials (recommended) or PySide6 — provides the Qt runtime plugins needed at runtime. This package only ships the QML styling files (no compiled plugin binaries), keeping the wheel small and cross-platform.
Public API reference
fluentpyside.apply() -> str
One-liner to enable the FluentWinUI3 theme. Call this before loading any QML. Returns the path used for the style.
import fluentpyside
fluentpyside.apply() # call BEFORE engine.load()
fluentpyside.set_style(engine=None, path=None) -> str
Lower-level API if you need fine-grained control. Sets the QML import path and Qt Quick Controls 2 style.
engine = QQmlApplicationEngine()
style_path = fluentpyside.set_style(engine=engine)
engine.load("main.qml")
fluentpyside.install_assets(target_dir)
Copy the FluentWinUI3 QML tree into a target project directory. Useful for vendoring the theme files.
python -m fluentpyside --install /path/to/your/project
fluentpyside.find_installed_style() -> Optional[Path]
Search for the FluentWinUI3 style in the installed PySide6 package. Returns None if not found.
fluentpyside.default_style_path() -> Path
Return the package-local style path (inside the fluentpyside wheel).
Common mistakes
❌ "ReferenceError: Fluent is not defined"
Make sure you call fluentpyside.apply() before loading your QML. The Fluent singleton is only available after the style is applied:
engine = QQmlApplicationEngine()
fluentpyside.apply() # ✅ Fluent singleton is now available
engine.load("main.qml")
❌ Using Qt Widgets instead of Qt Quick
This library styles Qt Quick Controls 2 (QML) only. It does nothing for classic Qt Widgets:
# ❌ These are Qt Widgets — NOT styled by fluentpyside
from PySide6.QtWidgets import QPushButton, QLabel, QMainWindow
# ✅ Use QML with PySide6 — this IS styled
from PySide6.QtQml import QQmlApplicationEngine
❌ Calling apply() after loading QML
fluentpyside.apply() must be called before engine.load():
engine = QQmlApplicationEngine()
fluentpyside.apply() # ✅ BEFORE
engine.load("main.qml")
# NOT:
# engine.load("main.qml") # ❌ too late
# fluentpyside.apply()
❌ Forgetting PySide6-Essentials
This package only ships QML files. You need PySide6 installed for the runtime:
pip install PySide6-Essentials # or PySide6 (full)
pip install fluentpyside
Updating the theme in a project
If you want to copy the FluentWinUI3 QML tree into a target project manually:
python tools/update_theme.py /path/to/your/project
This copies FluentWinUI3/ into /path/to/your/project/QtQuick/Controls/FluentWinUI3/ so you can add the project root as a QML import path.
License
- Wrapper: MIT License (file LICENSE)
- Upstream QML assets: copied from the locally installed PySide6 / PySide6-Essentials package. Follow Qt/PySide licensing when redistributing.
Metadata
Release files for fluentpyside 0.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| fluentpyside-0.2.1.tar.gz | 2.0 MB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| fluentpyside-0.2.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 4.9 MB
Release files / fluentpyside-0.2.1.tar.gz
| Download URL | fluentpyside-0.2.1.tar.gz |
|---|---|
| Size | 2.0 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e58e9fb0f27b9f801ad55fafd6405ad8fdca01899121dda583be20e47c933941
|
|
BLAKE2b-256 checksum How to use checksums |
5a9b292492fc0ee58d44c638acb31c9d94d3414d6b1e1b2d7d7d0c4ca2a97d55
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.5
|
Release files / fluentpyside-0.2.1-py3-none-any.whl
| Download URL | fluentpyside-0.2.1-py3-none-any.whl |
|---|---|
| Size | 2.9 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
115c19c4d4abb26aeda2130abdc1b83cc9b676049724860b37b042d37dcbb8f8
|
|
BLAKE2b-256 checksum How to use checksums |
0474654e6a1bbb79848d6de505d489ce6fc4f5a7256148fc46924c227fff9dd1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.5
|
Security for fluentpyside 0.2.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.