StyleKit Property Resolution | Qt Labs StyleKit | Qt 6.11.2
Description: How StyleKit resolves style property values.

- Qt 6.11
- Qt Labs StyleKit
- StyleKit Property Resolution
- Qt 6.11.2 Reference Documentation

# StyleKit Property Resolution

A style property — such as background.color — can have many different values depending on the control's state, the active Theme, and effective style variations. For example, it can differ between the pressed and hovered states, or between the light and dark themes. This document details how `StyleKit` resolves the value a property will get when used for styling a particular Control.

## Control States

Controls change appearance depending on interaction — hovered, pressed, checked, focused, disabled, and so on. When resolving a property, `StyleKit` exhausts all state-specific values first, before checking the normal state.

For example, if a Button is hovered, `hovered.button.background.color` is checked before `button.background.color`. And if it's also pressed, `pressed.button.background.color` is checked before them both. The order of precedence between states is documented in the ControlStateStyle documentation.

States can also be nested. A combination such as `pressed.hovered.button.background.color` is more specific than either `pressed.button.background.color` or `hovered.button.background.color` alone, and takes precedence over both.

## Fallback Properties

Some style properties can be set more than one way. For example, the top-left radius on the background can be set either directly using background.topLeftRadius, or indirectly using background.radius (which sets all corners to the same radius). For such properties, `StyleKit` checks the specific property first, then the fallback, and exhausts both within the current state before moving to a less specific state. For example, `button.hovered.background.radius` takes precedence over `button.background.topLeftRadius`, if the control is hovered. And of course, `button.hovered.background.topLeftRadius` takes precedence over both.

## Control Type Hierarchy

The controls form a hierarchy. A button falls back to abstractButton, which falls back to control. A groupBox falls back to frame, which falls back to pane, which falls back to control, and so on. `control` is the root type in the hierarchy, mirroring the type hierarchy of Qt Quick Controls. Refer to the documentation for each control type to see its direct fallback type.

When all states and fallback properties have been exhausted for a specific control type, `StyleKit` walks up the hierarchy to check whether it is set in a base type. For example, if `button.background.color` is not set, `StyleKit` will check `abstractButton.background.color` instead, and so on. This motivates the designer to factor the property values that are common across multiple controls into a common base type, to maximize reuse and minimize duplication. For example, you can put all the property values common to buttons, checkboxes, and radio buttons in `abstractButton`, and only set the properties that differ in the specific subtypes.

Note that any state (including the normal state) in a more specific type takes precedence over any state in a base type. For example, `button.background.color` takes precedence over `hovered.abstractButton.background.color`, even if the control is hovered. And of course, `hovered.button.background.color` takes precedence over both.

## Style And Theme

The Control Type Hierarchy is repeated inside both a Style and a Theme. When resolving a property, `StyleKit` first looks through the control type hierarchy in the active Theme, then in the active Style. This means that properties set in the active theme take precedence over those set in the style. As a consequence, a base type in the theme also overrides a more specific type in the style. For example, `theme.control.background.color` takes precedence over `style.button.background.color`.

## Style Variations

The Control Type Hierarchy is repeated inside a StyleVariation. Style variations can be defined both in a style and in a theme, and a style variation in a theme takes precedence over the theme itself. Since a theme takes precedence over a style, the style properties in the current theme will also take precedence over style variations in the style. For example, `theme.button.background.color` takes precedence over `style.variation.button.background.color`.

## Fallback Style

Every Style has a fallback style — a complete style that acts as a last resort when a property cannot be resolved within the active style. If the full resolution process (across control types, states, the active theme, and any style variations) fails to find a value, `StyleKit` repeats the entire process in the fallback style. The default fallback style looks similar to the Basic Style, so even an empty style will still produce fully styled controls.

The fallback style can itself have a fallback style, and `StyleKit` follows this chain recursively until it either finds a value or exhausts the chain. If no value is found, a default value is used.

## Putting It All Together

As an example, let's say `StyleKit` needs to resolve `background.color` for a hovered Button. The style has a theme, and both the style and the theme have an active variation. `StyleKit` then checks the following locations in order, using the first value it finds:

- `theme.variation.hovered.button.background.color`
- `theme.variation.button.background.color`
- `theme.variation.hovered.abstractButton.background.color`
- `theme.variation.abstractButton.background.color`
- `theme.variation.hovered.control.background.color`
- `theme.variation.control.background.color`
- `theme.hovered.button.background.color`
- `theme.button.background.color`
- `theme.hovered.abstractButton.background.color`
- `theme.abstractButton.background.color`
- `theme.hovered.control.background.color`
- `theme.control.background.color`
- `style.variation.hovered.button.background.color`
- `style.variation.button.background.color`
- `style.variation.hovered.abstractButton.background.color`
- `style.variation.abstractButton.background.color`
- `style.variation.hovered.control.background.color`
- `style.variation.control.background.color`
- `style.hovered.button.background.color`
- `style.button.background.color`
- `style.hovered.abstractButton.background.color`
- `style.abstractButton.background.color`
- `style.hovered.control.background.color`
- `style.control.background.color`

If all these locations are exhausted without finding a value, the same process is repeated in the fallback style (recursively, if the fallback style also has a fallback style). If still not found, a default value is used.

## Debugging Property Resolution

With multiple control types, themes, variations, and fallback styles all contributing to the final value of a property, it can sometimes be hard to tell why a particular control ends up with a particular appearance. StyleKitDebug is a diagnostic in-app tool that logs each style property read to the debug output, showing exactly which layer and control type a property was resolved from.

To start tracing, assign the control you want to introspect to the StyleKit.debug.control property:

     ApplicationWindow {
         id: app
         width: 1024
         height: 800
         visible: true

         StyleKit.debug.control: someButton
         StyleKit.debug.filter: "background.color"

         StyleKit.style: Style {
             button {
                 background.color: "gray"
                 hovered.background.color: "dimgray"
             }
             dark: Theme {
                 button {
                     background.color: "skyblue"
                     hovered.background.color: "lightblue"
                 }
             }
         }

         Column {
             anchors.fill: parent
             anchors.margins: 10
             spacing: 10

             Button {
                 id: someButton
                 text: "A Button"
             }
         }
     }

Each resolved property is printed as a single line, for example:

     [read] StyleReader[Hovered].button.background.color -> Style.Theme(Dark).button[Hovered] = #add8e6

The `StyleReader` in the output refers to the StyleReader that the Button uses internally to read its style property values.

Use the filter property to limit the output to properties of interest.

Note: Enabling StyleKitDebug will severely degrade performance. Use it only during debugging.

See also Style, Theme, StyleVariation, StyleKitDebug, and StyleKit Features Overview.