Expanded Client Areas and Safe Areas
March 27, 2025 by Tor Arne Vestbø | Comments
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.
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
Subscribe to our newsletter
Subscribe Newsletter
Try Qt 6.8 Now!
Download the latest release here: www.qt.io/download.
Qt 6.8 release focuses on technology trends like spatial computing & XR, complex data visualization in 2D & 3D, and ARM-based development for desktop.
We're Hiring
Check out all our open positions here and follow us on Instagram to see what it's like to be #QtPeople.
This is really useful! Thanks.
Thanks Philip!
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
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 useUIStatusBarStyleDefault
.Fantastic! The edge-to-edge on mobile adds some nice polish to Qt apps.
Thanks James!
Is this only for Qt Quick? will it be added to Qt Widgets?
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, unlessQt::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!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.
Correct, this is a 6.9 feature.
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?
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