Spellchecking with QML

QML is a nice technology but it sometimes feels that some parts of KDE Frameworks aren’t neatly integrated with it. For example, until recently KNotification didn’t have QML bindings, which was the same for KSyntaxHighlighting. Thankfully Volker Krause took care of both.

Another part of the often-used KDE Frameworks but had missing QML bindings was Sonnet. Sonnet is a very nice KDE framework powering KDE text areas with spell checking.

The good news, Sonnet will, in the next KF5 release, supports QML apps too!

Spell checking in NeoChat
Spell checking in NeoChat

There are two ways to add Sonnet supports in your application.

The easy way: Kirigami and qqc2-desktop-theme integration

If you use Kirigami and are fine with the default behavior, this only needs one single line in your QtQuick.Controls.TextArea.

import org.kde.kirigami 2.18 as Kirigami

import QtQuick.Controls 2.15 as QQC2

QQC2.TextArea {
    Kirigami.SpellChecking.enabled: true

This line is just a hint for the QtQuick Controls 2 theme to enable spell checking for this TextArea. Currently, only the qqc2-desktop-theme uses this hint. For other themes, like qqc2-breeze-style or custom themes, this will unfortunately do nothing.

This hint is required since we decided to disable spell checking by default. This is because of multiple reasons: this might cause some breakage for apps that are already doing its own TextArea modification.

The hard but powerful way

The second way to add spellchecking with Sonnet is to use the bindings directly. This makes it possible to configure the exact behavior of the spellchecking in your app. This is the API that qqc2-desktop-theme is using internally.

For that, you will then need to add the SpellcheckHighlighter directly to your TextArea.

import org.kde.kirigami 2.18 as Kirigami
import QtQuick.Controls.Template 2.15 as T

T.TextArea {
    id: controlRoot
    Sonnet.SpellcheckHighlighter {
        id: spellcheckhighlighter
        document: controlRoot.textDocument
        cursorPosition: controlRoot.cursorPosition
        selectionStart: controlRoot.selectionStart
        selectionEnd: controlRoot.selectionEnd
        misspelledColor: Kirigami.Theme.negativeTextColor

        onChangeCursorPosition: {
            controlRoot.cursorPosition = start;
            controlRoot.moveCursorSelection(end, TextEdit.SelectCharacters);

Sonnet.SpellcheckHighlighter exposes a few interesting methods that make it possible to get the spellchecker’s suggestions, add words to the dictionary, ignore some words and more. For those interested, I would recommend looking inside qqc2-desktop-theme and see how Sonnet is used. Settings

Sonnet now also exports the spell-checking options to QML. You can find an example of how to use the exposed config object in NeoChat. I hope to move this code at some point in Kirigami Addons, so that not every app will need to implement its own setting config page.

NeoChat Spellchecking options
NeoChat Spellchecking options

This change opens the way to also port the global spell-checking options in Plasma System Settings to QML in the future. Next plans

My next plan to make QML powerful in KDE is to figure out a way to upstream the nice KXMLGui/KConfigWidgets that I build for Kalendar into a separate component/library. This would make it possible to use a command bar, global menu bar, normal menu bar, configurable shortcuts and possibly more in a QML/Kirigami app.

This one is a bit tricky since dependency wise. Since all these features depends on QAction that depends directly on QtWidgets in Qt5. In Qt6 this now only depends on QtGUI but is is sill annoying that QAction can’t be used in QML but instead we have a QQuickAction that is part of the private QtQuick Controls 2 API.


With an account on the Fediverse or Mastodon, you can respond to this post. Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one. Known non-private replies are displayed below.

Learn how this is implemented here.

Licensed under CC BY-SA 4.0