A QML document has imports followed by one root object.
Ids are local lexical references, not runtime string properties.
import QtQuick
Item {
id: root
property int count: 0
readonly property int doubled: root.count * 2
signal accepted(int count)
function reset(): void {
root.count = 0
}
}
Prefer concrete property types because they document intent and improve tooling.
Use required for values every component instance must receive.
Use readonly for externally immutable values, including derived bindings.
Imports
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import "controls" as AppControls
import "format.js" as Format
Use versionless imports for normal Qt 6 code unless the repository intentionally restricts the imported API.
A version is a compatibility constraint, not a general stability improvement.
ApplicationWindow comes from QtQuick.Controls.
Window comes from QtQuick.Window.
A binding re-evaluates when QML properties read by its expression change.
Mutation inside a plain JavaScript object is not a QML property notification, so replace the object or expose observable properties.
Use ids, required properties, or signals for cross-object communication.
Ancestor walks such as parent.parent.value make geometry and state structure accidentally coupled.
# Syntax and bindings
Use the official QML language reference for grammar and type details:
<https://doc.qt.io/qt-6/qtqml-syntax-basics.html>.
## File shape
A QML document has imports followed by one root object.
Ids are local lexical references, not runtime string properties.
```qml
import QtQuick
Item {
id: root
property int count: 0
readonly property int doubled: root.count * 2
signal accepted(int count)
function reset(): void {
root.count = 0
}
}
```
Prefer concrete property types because they document intent and improve tooling.
Use `required` for values every component instance must receive.
Use `readonly` for externally immutable values, including derived bindings.
## Imports
```qml
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import "controls" as AppControls
import "format.js" as Format
```
Use versionless imports for normal Qt 6 code unless the repository intentionally restricts the imported API.
A version is a compatibility constraint, not a general stability improvement.
`ApplicationWindow` comes from `QtQuick.Controls`.
`Window` comes from `QtQuick.Window`.
## Binding versus assignment
```qml
width: parent.width / 2 // binding
Component.onCompleted: width = 200 // assignment replaces that binding
Component.onCompleted: width = Qt.binding(() => parent.width / 3)
```
A binding re-evaluates when QML properties read by its expression change.
Mutation inside a plain JavaScript object is not a QML property notification, so replace the object or expose observable properties.
Use ids, required properties, or signals for cross-object communication.
Ancestor walks such as `parent.parent.value` make geometry and state structure accidentally coupled.