QML Best Practices: Coding Standards and Structuring
Coding standards contribute to better code quality, readability, maintainability, and collaboration, resulting in more efficient and reliable software development processes. This document provides a comprehensive overview of the QML coding standards and guidelines employed at Invisto.
This document has been created through our findings over the years, as well as by incorporating advice from the Qt Group and the Open Source community.
1. File Organization and Project Structure
1.1 Separate Files
Keep each major component in its own QML file. For example, create separate files for main views, reusable components, and utility functions.
1.2 Naming Conventions
- Name files after the main component within them, using PascalCase for components (e.g.,
MainView.qml
). - Keep filenames consistent with component names to avoid confusion.
1.3 Directory Structure
- Group related components within folders. For example:
views/
for main view components.components/
for reusable or smaller UI elements.models/
for data models.utils/
for utility functions.
2. Component Structure and Layout
2.1 Minimize Nesting
Avoid excessive nesting of QML elements to keep the hierarchy manageable and improve performance.
2.2 Consistent Root Element Naming
Name the root element in each QML file as root
to simplify referencing the main container, improve readability, and standardize access patterns across the codebase.
2.3 Encapsulating Internal Data
Use a private QtObject
within a component to manage internal data. This approach helps encapsulate component-specific logic and keeps the internal data separate from the UI elements, ensuring a clear separation of concerns.
2.4 Use Aliases and Properties
- Use
property alias
andproperty
for exposing internal properties to parent components. - Avoid direct element access from outside of a component; instead, expose values through properties to improve encapsulation.
2.5 Default Properties
- Set default values to properties when possible to simplify usage.
- Prefer enums for state management and property values to improve readability.
3. Translations
3.1 Marking Translatable Text
Use qsTr
for all translatable strings to mark them clearly for the Qt translation system.
3.2 Untranslated Text Indicators
Ensure untranslated text is easily recognizable by using uppercase (e.g., "HELLO"
in place of "Hello"
), which helps identify missing translations and simplifies localization efforts.
4. Styling and Reusability
4.1 Use Item
as a Base
Use Item
as a container when you don’t need visual representation but require layout capabilities.
4.2 Stylesheets
Avoid inline styling; centralize styling to reusable stylesheets or global themes where possible.
4.3 Custom Components:
- Use custom QML components (or reusable components) for common UI patterns to keep code DRY (Don’t Repeat Yourself).
- For styling, create a separate
Theme.qml
orStyles.qml
for storing global colors, fonts, and paddings.
5. Naming Conventions
5.1 Identifiers
Use meaningful and self-explanatory names for objects, properties, and functions.
5.2 CamelCase vs. Snake_Case
- Use CamelCase for property names (e.g.,
backgroundColor
) and function names (e.g.,calculateWidth()
). - Use PascalCase for component names (e.g.,
MainView
).
6. Bindings and Expressions
6.1 Efficient Bindings
- Use
Connections
instead of directly connecting signals in JavaScript, as it offers better lifecycle management. - Avoid binding properties with complex expressions, which can slow down the application.
6.2 Use on
Properties for Changes
Use on<Property>Changed
handlers rather than directly binding property values when you need to execute custom logic on updates.
7. Logic in QML vs. C++
7.1 Minimize QML Logic
Avoid embedding too much logic directly in QML files. Delegate complex operations to C++ where feasible, which offers better performance, especially for intensive data processing tasks.
7.2 Modularize JavaScript Code
For non-performance-critical logic that must remain in QML, offload complex JavaScript code to separate .js
files for better organization.
8. Performance Optimization
8.1 Avoid Unnecessary Elements
Remove elements that are not essential, and only create objects when necessary.
8.2 Lazy Loading
Use Loader
to delay loading heavy components until they are needed. This improves initial load times.
8.3 Limit Visual Effects
Use effects like Opacity
, Blur
, or DropShadow
sparingly, as they are resource-intensive.
8.5 Anchors vs. Layouts
Use anchors
for simple layouts as they are more efficient than GridLayout
or ColumnLayout
.
9. State and Animation Management
9.1 Use States for UI Transitions
Define distinct states
in QML to manage different configurations of a component based on application state.
9.2 Declarative Animations
Use declarative animations (e.g., Behavior
or Transition
) to animate properties. Avoid procedural animations in JavaScript unless necessary.
9.3 Avoid Over-Animating
Keep animations subtle and sparing, as too many can distract users and impact performance.
10. Error Handling and Debugging
10.1 QML Warnings
Pay attention to warnings in the console to catch deprecations or performance issues.
10.2 Debugging
Use console.log()
for debugging values in QML.
10.3 Error Management
Check for undefined properties or undefined bindings, especially in dynamically created components.
11. Documentation, Comments, and Linting
11.1 Document Each Component
Briefly describe the purpose of each component at the top of the file.
11.2 Comment Inline
Explain complex bindings, transitions, or property changes with short comments to help future developers.
11.3 Consistent Formatting
Format code consistently with spacing and indentation for readability.
11.4 Linting
Run qmllint
to check for syntax issues, unused imports, and other potential problems in QML files. This tool helps catch issues early and maintain consistent quality across the codebase.
12. Testing and Maintenance
12.1 Use Property Tests
Use property-based testing to validate components’ behaviors, especially for properties affected by bindings or animations.
12.2 Automated UI Testing
Utilize Qt Test and Squish(or other tools compatible with QML) for automated UI testing to ensure component reliability.