Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qtlabsstylekit-propagation.qdoc
Go to the documentation of this file.
1// Copyright (C) 2026 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
3
4/*!
5 \page qtlabsstylekit-propagation.html
6 \title StyleKit Property Resolution
7 \brief How StyleKit resolves style property values.
8
9 A style property — such as \l {DelegateStyle::color}{background.color} — can have
10 many different values depending on the control's \l {StyleReader}{state}, the active \l Theme, and
11 effective \l {StyleVariation}{style variations}.
12 For example, it can differ between the \l {ControlStateStyle::}{pressed} and
13 \l {ControlStateStyle::}{hovered} states, or between the \l {Style::light}{light}
14 and \l {Style::dark}{dark} themes.
15 This document details how \c StyleKit resolves the value a property will get when
16 used for styling a particular \l [QtQuickControls]{Control}.
17
18 \section1 Control States
19
20 Controls change appearance depending on interaction —
21 \l {ControlStateStyle::}{hovered}, \l {ControlStateStyle::}{pressed},
22 \l {ControlStateStyle::}{checked}, \l {ControlStateStyle::}{focused},
23 \l {ControlStateStyle::}{disabled}, and so on. When resolving a property, \c StyleKit exhausts all
24 state-specific values first, before checking the normal state.
25
26 For example, if a \l [QtQuickControls]{Button} is \l {ControlStateStyle::}{hovered},
27 \c {hovered.button.background.color} is checked before \c {button.background.color}.
28 And if it's also \l {ControlStateStyle::}{pressed}, \c {pressed.button.background.color}
29 is checked before them both. The order of precedence between states is documented in
30 the \l {ControlStateStyle}{ControlStateStyle documentation}.
31
32 States can also be nested. A combination such as \c {pressed.hovered.button.background.color}
33 is more specific than either \c {pressed.button.background.color} or \c {hovered.button.background.color}
34 alone, and takes precedence over both.
35
36 \section1 Fallback Properties
37
38 Some style properties can be set more than one way. For example, the top-left radius
39 on the background can be set either directly using
40 \l {DelegateStyle::topLeftRadius}{background.topLeftRadius}, or
41 indirectly using \l {DelegateStyle::radius}{background.radius} (which sets all corners
42 to the same radius). For such properties, \c StyleKit checks the specific property
43 first, then the fallback, and exhausts both within the current state before moving to
44 a less specific state. For example, \c {button.hovered.background.radius} takes
45 precedence over \c {button.background.topLeftRadius}, if the control is hovered.
46 And of course, \c {button.hovered.background.topLeftRadius} takes precedence over both.
47
48 \section1 Control Type Hierarchy
49
50 \l {AbstractStylableControls}{The controls} form a hierarchy. A \l {AbstractStylableControls::button}{button}
51 falls back to \l {AbstractStylableControls::abstractButton}{abstractButton}, which
52 falls back to \l {AbstractStylableControls::control}{control}.
53 A \l {AbstractStylableControls::groupBox}{groupBox} falls back to
54 \l {AbstractStylableControls::frame}{frame}, which falls back to
55 \l {AbstractStylableControls::pane}{pane}, which falls back to
56 \l {AbstractStylableControls::control}{control}, and so on.
57 \c control is the root type in the hierarchy, mirroring the type
58 hierarchy of \l {Qt Quick Controls}. Refer to the \l {AbstractStylableControls}{documentation}
59 for each control type to see its direct fallback type.
60
61 When all states and fallback properties have been exhausted for a specific control type,
62 \c StyleKit walks up the hierarchy to check whether it is set in a base type.
63 For example, if \c {button.background.color} is not set, \c StyleKit will check
64 \c {abstractButton.background.color} instead, and so on.
65 This motivates the designer to factor the property values that are common across multiple
66 controls into a common base type, to maximize reuse and minimize duplication. For example, you
67 can put all the property values common to buttons, checkboxes, and radio buttons in
68 \c abstractButton, and only set the properties that differ in the specific subtypes.
69
70 Note that any state (including the normal state) in a more specific type takes precedence over
71 any state in a base type. For example, \c {button.background.color} takes
72 precedence over \c {hovered.abstractButton.background.color}, even if the control is hovered.
73 And of course, \c {hovered.button.background.color} takes precedence over both.
74
75 \section1 Style And Theme
76
77 The \l {Control Type Hierarchy} is repeated inside both a \l Style and a \l Theme.
78 When resolving a property, \c StyleKit first looks through the control type hierarchy in
79 the active \l Theme, then in the active \l Style.
80 This means that properties set in the active theme take precedence over those set in the style.
81 As a consequence, a base type in the theme also overrides a more specific type in the style. For
82 example, \c {theme.control.background.color} takes precedence over \c {style.button.background.color}.
83
84 \section1 Style Variations
85
86 The \l {Control Type Hierarchy} is repeated inside a \l StyleVariation.
87 Style variations can be defined both in a style and in a theme, and a style variation in a theme
88 takes precedence over the theme itself. Since a theme takes precedence over a style, the style
89 properties in the current theme will also take precedence over style variations in the style.
90 For example, \c {theme.button.background.color} takes precedence over
91 \c {style.variation.button.background.color}.
92
93 \section1 Fallback Style
94
95 Every \l Style has a \l {Style::fallbackStyle}{fallback style} — a complete style
96 that acts as a last resort when a property cannot be resolved within the active style.
97 If the full resolution process (across control types, states, the active theme, and any
98 style variations) fails to find a value, \c StyleKit repeats the entire process in the
99 fallback style. The default fallback style looks similar to the \l {Basic Style}, so even
100 an empty style will still produce fully styled controls.
101
102 The fallback style can itself have a fallback style, and \c StyleKit follows this chain
103 recursively until it either finds a value or exhausts the chain. If no value is found, a
104 default value is used.
105
106 \section1 Putting It All Together
107
108 As an example, let's say \c StyleKit needs to resolve \c {background.color} for a
109 \l {ControlStateStyle::}{hovered} \l [QtQuickControls]{Button}. The style has a theme, and both
110 the style and the theme have an active variation. \c StyleKit then checks the following locations
111 in order, using the first value it finds:
112
113 \list
114 \li \c {theme.variation.hovered.button.background.color}
115 \li \c {theme.variation.button.background.color}
116 \li \c {theme.variation.hovered.abstractButton.background.color}
117 \li \c {theme.variation.abstractButton.background.color}
118 \li \c {theme.variation.hovered.control.background.color}
119 \li \c {theme.variation.control.background.color}
120 \li \c {theme.hovered.button.background.color}
121 \li \c {theme.button.background.color}
122 \li \c {theme.hovered.abstractButton.background.color}
123 \li \c {theme.abstractButton.background.color}
124 \li \c {theme.hovered.control.background.color}
125 \li \c {theme.control.background.color}
126 \li \c {style.variation.hovered.button.background.color}
127 \li \c {style.variation.button.background.color}
128 \li \c {style.variation.hovered.abstractButton.background.color}
129 \li \c {style.variation.abstractButton.background.color}
130 \li \c {style.variation.hovered.control.background.color}
131 \li \c {style.variation.control.background.color}
132 \li \c {style.hovered.button.background.color}
133 \li \c {style.button.background.color}
134 \li \c {style.hovered.abstractButton.background.color}
135 \li \c {style.abstractButton.background.color}
136 \li \c {style.hovered.control.background.color}
137 \li \c {style.control.background.color}
138 \endlist
139
140 If all these locations are exhausted without finding a value, the same process is
141 repeated in the fallback style (recursively, if the fallback style also has a fallback
142 style). If still not found, a default value is used.
143
144 \section1 Debugging Property Resolution
145
146 With multiple control types, themes, variations, and fallback styles all
147 contributing to the final value of a property, it can sometimes be hard to
148 tell why a particular control ends up with a particular appearance.
149 \l StyleKitDebug is a diagnostic in-app tool that logs each style property
150 read to the debug output, showing exactly which layer and control type a
151 property was resolved from.
152
153 To start tracing, assign the control you want to introspect to the
154 \l {StyleKitDebug::control}{StyleKit.debug.control} property:
155
156 \snippet StyleKitDebug.qml trace
157
158 Each resolved property is printed as a single line, for example:
159
160 \code
161 [read] StyleReader[Hovered].button.background.color -> Style.Theme(Dark).button[Hovered] = #add8e6
162 \endcode
163
164 The \c StyleReader in the output refers to the \l StyleReader that the \l Button
165 uses internally to read its style property values.
166
167 Use the \l {StyleKitDebug::filter}{filter} property to limit the output to properties of interest.
168
169 \note Enabling \l StyleKitDebug will severely degrade performance. Use it
170 only during debugging.
171
172 \sa Style, Theme, StyleVariation, StyleKitDebug, {StyleKit Features Overview}
173*/