name: qml
description: "Use when writing or editing QML and Qt Quick code, including bindings, signals, components, layouts, models, Controls, focus, keyboard input, and accessibility."
QML
QML declares an object tree whose property bindings react to dependency changes.
Keep presentation declarative and keep state ownership explicit.
Workflow
Inspect the surrounding component, its callers, imports, and the project's Qt version and tooling.
Verify the executable's Qt major version; on Arch the bare qmllint may be Qt5, while /usr/lib/qt6/bin/qmllint is Qt6.
Name the owner of each piece of state and each item's geometry before editing.
Reuse an existing Qt Quick Control or project component before building interaction from primitives.
Bind owned state down into children and send user intent up through signals or narrowly scoped handlers.
Run qmllint with the project's import paths.
Load changed entry points using the project's isolated runtime and inspect complete logs for creation, import, binding-loop, and layout failures.
Plain Qt Quick windows can load offscreen; toolkit windows such as Quickshell panels need their supported backend.
Exercise changed interaction with an existing test or UI driver when the task requires behavioral verification.
For toolkit integrations, follow their official editor/LSP setup before diagnosing incomplete metadata as broken QML.
Consult the installed Qt documentation or https://doc.qt.io/qt-6/ for type-specific APIs.
Do not duplicate volatile property lists from memory.
Invariants
Give mutable state one owner.
Derived values stay bindings, and user events update the owner rather than sibling copies.
Give geometry one owner per axis.
A layout, anchors, or explicit coordinates may own an axis, not several at once.
Treat imperative assignment to a bound property as binding replacement.
Assign the binding's dependency or restore it explicitly with Qt.binding(...) when replacement is intentional.
Use ids within a component, and required properties or signals across component boundaries.
Do not navigate with parent.parent.
Prefer QtQuick.Controls for buttons, fields, toggles, menus, and other standard interaction because Controls provide platform behavior, keyboard handling, focus, and accessibility semantics.
Give controls and custom interactive items meaningful accessible names when visible text does not already supply one.
Verify Tab, Shift+Tab, arrow-key, Enter/Space, Escape, and shortcut flows that apply.
A Keys handler only receives events while its item has active focus.
Keep focus visible.
Do not remove a Control's focus indicator without an accessible replacement.
Load the gestalt skill for actual visual organization, hierarchy, grouping, or layout design.
This skill governs QML mechanics, not visual judgment.
Imports
Use versionless Qt imports in a Qt 6 application unless the project deliberately targets an older import version.
Versioned imports restrict the API visible to QML, so copy the repository's established policy rather than pinning every import.
The binding keeps the Slider synchronized from its owner.
onMoved writes only user movement back to the owner, unlike onValueChanged, which also runs for programmatic changes.
Writing root.volume does not break the binding on value; writing value imperatively does.
Deferred and asynchronous work
Qt.callLater(callback, ...args) schedules a callback for a later event-loop turn and coalesces repeated calls to the same function, using the last supplied arguments.
It does not create or return a Promise and does not make blocking work asynchronous.
Use the project's C++ or service boundary for I/O and expensive work.
A clean offscreen startup confirms that the entry point imports and instantiates.
Timeout exit status 124 is expected for a window that remains in its event loop.
Offscreen loading does not verify clicks, keys, focus traversal, accessibility output, animations, or rendered appearance.
Claim interaction only after a Qt Quick Test or an existing UI automation route actually exercises it.
---
name: qml
description: "Use when writing or editing QML and Qt Quick code, including bindings, signals, components, layouts, models, Controls, focus, keyboard input, and accessibility."
---
# QML
QML declares an object tree whose property bindings react to dependency changes.
Keep presentation declarative and keep state ownership explicit.
## Workflow
1. Inspect the surrounding component, its callers, imports, and the project's Qt version and tooling.
Verify the executable's Qt major version; on Arch the bare `qmllint` may be Qt5, while `/usr/lib/qt6/bin/qmllint` is Qt6.
2. Name the owner of each piece of state and each item's geometry before editing.
3. Reuse an existing Qt Quick Control or project component before building interaction from primitives.
4. Bind owned state down into children and send user intent up through signals or narrowly scoped handlers.
5. Run `qmllint` with the project's import paths.
6. Load changed entry points using the project's isolated runtime and inspect complete logs for creation, import, binding-loop, and layout failures.
Plain Qt Quick windows can load offscreen; toolkit windows such as Quickshell panels need their supported backend.
7. Exercise changed interaction with an existing test or UI driver when the task requires behavioral verification.
For toolkit integrations, follow their official editor/LSP setup before diagnosing incomplete metadata as broken QML.
Consult the installed Qt documentation or <https://doc.qt.io/qt-6/> for type-specific APIs.
Do not duplicate volatile property lists from memory.
## Invariants
- Give mutable state one owner.
Derived values stay bindings, and user events update the owner rather than sibling copies.
- Give geometry one owner per axis.
A layout, anchors, or explicit coordinates may own an axis, not several at once.
- Treat imperative assignment to a bound property as binding replacement.
Assign the binding's dependency or restore it explicitly with `Qt.binding(...)` when replacement is intentional.
- Use ids within a component, and required properties or signals across component boundaries.
Do not navigate with `parent.parent`.
- Prefer `QtQuick.Controls` for buttons, fields, toggles, menus, and other standard interaction because Controls provide platform behavior, keyboard handling, focus, and accessibility semantics.
- Give controls and custom interactive items meaningful accessible names when visible text does not already supply one.
- Verify Tab, Shift+Tab, arrow-key, Enter/Space, Escape, and shortcut flows that apply.
A `Keys` handler only receives events while its item has active focus.
- Keep focus visible.
Do not remove a Control's focus indicator without an accessible replacement.
- Load the `gestalt` skill for actual visual organization, hierarchy, grouping, or layout design.
This skill governs QML mechanics, not visual judgment.
## Imports
Use versionless Qt imports in a Qt 6 application unless the project deliberately targets an older import version.
Versioned imports restrict the API visible to QML, so copy the repository's established policy rather than pinning every import.
```qml
import QtQuick
import QtQuick.Controls // ApplicationWindow, Button, TextField, Slider
import QtQuick.Layouts // RowLayout, ColumnLayout, GridLayout, StackLayout
import QtQuick.Window // Window
```
## State and events
```qml
import QtQuick
import QtQuick.Controls
ApplicationWindow {
id: root
width: 400
height: 240
visible: true
property real volume: 0.5
Slider {
anchors.centerIn: parent
value: root.volume
Accessible.name: "Volume"
onMoved: root.volume = value
}
}
```
The binding keeps the Slider synchronized from its owner.
`onMoved` writes only user movement back to the owner, unlike `onValueChanged`, which also runs for programmatic changes.
Writing `root.volume` does not break the binding on `value`; writing `value` imperatively does.
## Deferred and asynchronous work
`Qt.callLater(callback, ...args)` schedules a callback for a later event-loop turn and coalesces repeated calls to the same function, using the last supplied arguments.
It does not create or return a Promise and does not make blocking work asynchronous.
Use the project's C++ or service boundary for I/O and expensive work.
## Validation levels
```sh
qmllint path/to/File.qml
QT_QPA_PLATFORM=offscreen timeout 3s qml6 path/to/File.qml
```
- `qmllint` is static analysis, not a load test.
- A clean offscreen startup confirms that the entry point imports and instantiates.
Timeout exit status `124` is expected for a window that remains in its event loop.
- Offscreen loading does not verify clicks, keys, focus traversal, accessibility output, animations, or rendered appearance.
- Claim interaction only after a Qt Quick Test or an existing UI automation route actually exercises it.
## References
- [Syntax and bindings](references/syntax.md)
- [Components](references/components.md)
- [Layouts and geometry](references/layouts.md)
- [Models and views](references/models.md)
- [Signals and input](references/signals.md)
- [JavaScript](references/javascript.md)
- [Common pitfalls](references/common-pitfalls.md)
- [Runnable examples](examples/)