Expanded Client Areas and Safe Areas

A staple of modern application design on desktop and mobile is that the content is front and center — with application and system UI elements seamlessly blending into the content in non-intrusive ways. We're now going to look at two new features of Qt 6.9 that help achieve this: expanded client areas, and safe areas.

Expanded client areas

Let's say we're building an application for dog lovers, showcasing our favorite photos. A minimal application might look something like this:

import QtQuick

Window {
    visible: true
    width: 800; height: 600
    Image {
    	anchors.fill: parent
        source: "https://placedog.net/800/600?r"
        fillMode: Image.PreserveAspectCrop
    }
}

Which would give us the following on macOS and iOS:

     

So far so good, our dog is mostly front and center. But there are a few UI elements competing for the attention, namely the window titlebar and controls on macOS; and the clock, WiFI and battery status on iOS. We can do better!

By adding the Qt.ExpandedClientAreaHint window flag, we can ask that the window's client area is expanded into areas that would normally be reserved for system UI elements.

Window {
    flags: Qt.ExpandedClientAreaHint | Qt.NoTitleBarBackgroundHint
    // ...
}

To hide the titlebar on macOS, we've also added the Qt.NoTitleBarBackgroundHint, which together gives us:

.    .

Much better! The content now stretches edge to edge, giving full focus to the golden fur of our friend.

Safe Areas

Now, with expanded client areas comes expanded responsibilities. Our application is now fighting for the same screen real-estate as system UI and controls, and the system UI will typically win. This means we need to take care not place important content in the areas where the system UI may potentially overlap it, as this would prevent the user from seeing or interacting with our content.

For example, we might want to introduce functionality to interact with our dog while we're away:

Window {
    // ...
    Item {
        anchors {
            left: parent.left; right: parent.right; top: parent.top
            margins: 10
        }
        Text {
            text: "🎾 Throw Ball"; color: "white"; font.pointSize: 18
            anchors. left: parent.left
        }
        Text {
            text: "Give Bone 🦴"; color: "white"; font.pointSize: 18
            anchors. right: parent.right
        }
    }
}

But this would clash with the system UI on both macOS and iOS:

To handle this, we use the new SafeArea attached property, which tells us how much we need to inset our  content to stay away from the "non-safe" areas of the window:

anchors {
    left: parent.left; right: parent.right; top: parent.top
    topMargin: 10 + parent.SafeArea.margins.top
    leftMargin: 10 + parent.SafeArea.margins.left
    rightMargin: 10 + parent.SafeArea.margins.right
}

This safely puts our buttons below the titlebar on macOS:  

And away from the status bar on iOS:

As you may have noticed, we also accounted for landscape mode, by including the left and right safe area margins:

Qt Quick Controls

So far our examples have used a plain Qt Quick Window, but a more realistic example will likely use ApplicationWindow from Qt Quick Controls, which comes with some additional bells and whistles for safe area handling.

If the Qt.ExpandedClientAreaHint window flag is set we will automatically extend the window's background to cover the entire window, while keeping content added to the content item within the safe areas of the window.

For the window's header, footer, and menu bar you are generally responsible for handling safe areas yourself. But, we've taught the built-in ToolBar and MenuBar types a few tricks, so the following code will automatically extend the toolbar's background to the top of the screen, while keeping the toolbar content in the safe area:

ApplicationWindow {
    visible: true
    width: 500; height: 700
    flags: Qt.ExpandedClientAreaHint | Qt.NoTitleBarBackgroundHint

    header: ToolBar {
        background: Rectangle {
            gradient: Gradient.PremiumDark
            opacity: 0.7
        }
        RowLayout {
            anchors.fill: parent
            Text {
                text: "🎾 Throw Ball"; color: "white"; font.pointSize: 18
                Layout.margins: 10
            }
            Text {
                text: "Give Bone 🦴"; color: "white"; font.pointSize: 18
                Layout.alignment: Qt.AlignRight; Layout.margins: 10
            }
        }
    }
    
    // ...
}

Finally, if you have content in your application window that you knowingly want to extend into the non-safe areas of the window, you can do so by overriding the padding properties of the window, for example:

ApplicationWindow {
    // ...
    topPadding: 0

    ListView {
        id: listView
        anchors.fill: parent
        model: 10
        delegate: Image {
            required property int index
            width: listView.width; height: 250
            source: "https://placedog.net/500/250?id=" + (index + 1)
        }
        topMargin: SafeArea.margins.top

        onTopMarginChanged: {
            // Keep content position stable
            if (!dragging && atYBeginning)
                contentY = -topMargin
        }
    }
}

Which extends the list view underneath the toolbar and into the non-safe areas, but accounts for the safe area margins by making sure the list view's origin is placed directly below the toolbar. 

Simulator Screen Recording - iPhone 16 Pro - 2025-03-26 at 16.39.18-1

This works because the toolbar itself reports additional safe area margins for any part of the toolbar that extends beyond the safe-area margins reported by the system, and these additional margins are taken into account when the ListView queries for the safe area margins. In effect the list view is agnostic to where the safe area margins are coming from.

You can use this technique to build container components that reflect the non-safe areas of the container to its children letting the children decide if and how to respect the safe area margins in their layout instead of putting explicit constraints on how the children are laid out.

Looking ahead

With the changes in 6.9 we have hopefully taken a good step towards enabling these UI paradigms in Qt  applications.

The features are available and supported on macOS, Windows, iOS, visionOS, and Android, and we're looking to add support for the rest of our supported platforms.

.   

The plan is also, once the dust settles, to automatically enable Qt.ExpandedClientAreaHint on some platforms, such as Android and iOS.

Please test and let us know of any issues you find, or if your use-case is not covered by the existing APIs.


Blog Topics:

Comments

Philip Schuchardt
2 points
5 days ago

This is really useful! Thanks.

Tor Arne Vestbø
0 points
5 days ago

Thanks Philip!

ekke gentz
2 points
5 days ago

great work. thx. will test later - have to test 6.8.3 first ;-) one question: will it be easy to colorize the statusbar (setting the background) on Android and ios ? to do this I used StatusBar by JP for Qt 5 and MobileUI by Emeric Grange for Qt 6 https://t1p.de/ekkeStatusbar

Tor Arne Vestbø
0 points
5 days ago

Thanks ekke! The question about status bar color is a good one. Qt 6.5 added a way for applications to request a specific color scheme (Application.styleHints.colorScheme = Qt.ColorScheme.Dark e.g.), so it would make sense to plumb that to specific status bar styles on iOS and Android. I'll look into that.

Edit: this works as expected on iOS already, since we plumb the color scheme to UIWindow.overrideUserInterfaceStyle and use UIStatusBarStyleDefault.

J
James Ballard
2 points
4 days ago

Fantastic! The edge-to-edge on mobile adds some nice polish to Qt apps.

Tor Arne Vestbø
0 points
4 days ago

Thanks James!

罗滋宽
0 points
4 days ago

Is this only for Qt Quick? will it be added to Qt Widgets?

Tor Arne Vestbø
0 points
4 days ago

In Qt Widgets safe areas are handled via the Qt::WA_ContentsMarginsRespectsSafeArea attribute, which incorporates the safe areas into the contents margins of the widget. If you're using a layout the layout will respect the contents rect, unless Qt::WA_LayoutOnEntireRect is set.

Initially we defaulted all widgets to have Qt::WA_ContentsMarginsRespectsSafeArea set, but as that made it cumbersome to knowingly put content in the non-safe areas, so after this change we only do it for top level windows. Should be coming to a release near your soon!

Nikita Guryanov
0 points
4 days ago

Is it an exclusive 6.9 feature or will it be included to LTS 6.8.4?

I really need this for Android SDK 35 w/o workarounds, but I want to stick with LTS for a couple of months.

Tor Arne Vestbø
0 points
4 days ago

Correct, this is a 6.9 feature.

Wang Gary
0 points
3 days ago

https://www.qt.io/hs-fs/hubfs/undefined-Mar-27-2025-10-49-16-2292-AM.jpeg?width=377&height=528&name=undefined-Mar-27-2025-10-49-16-2292-AM.jpeg

In this image it seems the application theme is dark (dark titlebar background with white text) but the title text on the system titlebar is also black which make the title text on the system titlebar unreadable. Is it a bug?

Tor Arne Vestbø
0 points
1 days ago

The screenshot was taken without setting Application.styleHints.colorScheme = Qt.ColorScheme.Dark, so the title text is indeed wrong. Good catch! The full example should give you the correct look: https://gist.github.com/torarnv/6923a4ae199d44b5763060be3c00d169