call_end

    • Pl chevron_right

      Alice Mikhaylenko: Libadwaita 1.9

      news.movim.eu / PlanetGnome • 1 day ago • 6 minutes

    Screenshot of Characters, libadwaita demo and Highscore, demoing AdwSidebar in each

    Another slow cycle, same as last time. Still, a few new things to showcase.

    Sidebars

    Screenshot of the new sidebar in libadwaita demo and Characters

    The most visible addition is the new sidebar widget. This is a bit confusing, because we already had widgets for creating windows with sidebars - AdwNavigationSplitView and AdwOverlaySplitView , but nothing to actually put into the sidebar pane. The usual recommendation is to build your own sidebar using GtkListBox or GtkListView , combined with the .navigation-sidebar style class.

    This isn't too difficult, but the result is zero consistency between different apps, not unlike what we had with GtkNotebook -based tabs in the past:

    Screenshot of sidebars in various apps: libadwaita demo (no icons, no sections), Characters (icons, sections with non-dimmed labels, thicker rows), Confy (thinner rows, icons, but no sections), Chronograph (no sections, icons, and bold text, also no selection), Foliate (sections with smaller dimmed labels, icons, thin rows), Files (sections with separators, thin rows with dimmed icons), Iotas (no sections, even more dimmed icons, thick rows, number badges on the right), Sysprof (sections as separators, non-dimmed icons, thin rows, still number badges)

    It's even worse on mobile. In the best scenario it will just be a strangely styled flat list. Sometimes it will also have selection, and depending on how it's implemented it may be impossible to activate the selected row, like in libadwaita demo.

    So we have a pre-built one now. It doesn't aim to support every single use case (sidebars can get very complex, see e.g. GNOME Builder ), but just to be good enough for the basic situations.

    How basic is basic? Well, it has selection, sections (with or without titles), tooltips, context menus, a drop target, suffix widgets at the end of each item's row, auto-activation when hovered during drag-n-drop.

    A more advanced feature is built-in search filter - via providing a GtkFilter and a placeholder page.

    And that's about it. There will likely be more features in future, like collapsible sections and drag source on items, rather than just a drop target, but this should already be enough for quite a lot of apps. Not everything, but that's not the goal here.

    Internally, it's using GtkListBox . This means that it doesn't scale to thousands of items the way GtkListView would, but we can have much tighter API and mobile integration.

    Now, let's talk about mobile. Ideally sidebars on mobile wouldn't really be sidebars at all. This pattern inherently requires a second pane, and falls apart otherwise. AdwNavigationSplitView already presents the sidebar pane as a regular page, so let's go further and turn sidebars into boxed lists. We're already using GtkListBox , after all.

    So - AdwSidebar has the mode property. When set to ADW_SIDEBAR_MODE_PAGE , it becomes a page of boxed lists - indistinguishable from any others. It hides item selection, but it's still tracked internally. It can still be changed programmatically, and changes when an item is activated. Once the sidebar mode is set back to ADW_SIDEBAR_MODE_SIDEBAR , it will reappear.

    Internally it's nothing special, as it just presents the same data using different widgets.

    The adaptive layouts page has a detailed example for how to create UIs like this, as well as the newly added section about overlay sidebars that don't change as drastically.

    View switcher sidebar

    Screenshot of AdwViewSwitcherSidebar in sidebar and page modes

    Once we have a sidebar, a rather obvious thing to do is to provide a GtkStackSidebar replacement. So AdwViewSwitcherSidebar is exactly that.

    It works with AdwViewStack rather than GtkStack , and has all the same features as existing view switcher, as well as an extra one - sections.

    To support that, AdwViewStackPage has new API for defining sections - the :starts-section and :section-title properties, while the AdwViewStack:pages ) model is now a section model.

    Like regular sidebars, it supports the boxed list mode and search filtering.

    Unlike other view switchers or GtkStackSidebar , it also exposes AdwSidebar 's item activation signal. This is required to make it work on mobile.

    Demo improvements

    The lack of sidebar was the main blocker for improving libadwaita demo in the past. Now that it's solved, the demo is at last, fully adaptive. The sidebar has been reorganized into sections, and has icons and search now.

    This also unblocks other potential improvements, such as having a more scalable preferences dialog .

    Reduced motion

    While there isn't any new API, most widgets with animations have been updated to respect the new reduced motion preference - mostly by replacing sliding/scaling animations with crossfades, or otherwise toning down animations when it's impossible:

    • AdwDialog open/close transitions are crossfades except for the swipe-to-close gesture
    • AdwBottomSheet transition is a crossfade when there's no bottom bar, and a slide without overshooting if there is
    • AdwNavigationView transition is a crossfade except when using the swipe gestures
    • AdwTabOverview transition is a crossfade

    AdwOverlaySplitView is unaffected for now. Same for toasts, those are likely small enough to not cause motion sickness. If it turns out to be a problem, it can be changed later.

    I also didn't update any of the deprecated widgets, like AdwLeaflet . Applications still using those should switch to the modern alternatives.

    The prefers-reduced-motion media feature is available for use from app CSS as well, following the GTK addition.

    Other changes

    • AdwAboutDialog rows that contain links have a context menu now. Link rows may become a public widget in future if there's interest.

      Screenshot of the Support Questions and Report an Issue rows in about dialog, with a context menu with the following entries: Open Link, Copy Link Address
    • GTK_DEBUG=builder diagnostics are now supported for all libadwaita widgets. This can be used to find places where <child> tags are used in UI when equivalent properties exist.

    • Following GTK, all GListModel implementations now come with :item-type and :n-item properties, to make it easier to use them from expressions.

    • The AdwTabView:pages model implements sections now: one for pinned pages and one for everything else.

    • AdwToggle has a new :description property that can be used to set accessible description for individual toggles separately from tooltips.

    • Adrien Plazas improved accessibility in a bunch of widgets. The majority of this work has been backported to 1.8.x as well. For example, AdwViewSwitcher and AdwInlineViewSwither now read out number badges and needs attention status.

    • AdwNoneAnimationTarget now exists for situations where animations are used as frame clock-based timers, as an alternative to using AdwCallbackAnimationTarget with empty callback.

    • AdwPreferencesPage will refuse to add children of types other than AdwPreferencesGroup , instead of overlaying them over the page and then leaking them after the page is destroyed. This change was backported to 1.8.2 and subsequently reverted in 1.8.3 as it turned out multiple apps were relying on the broken behavior.

    • Maximiliano made non-nullable string setter functions automatically replace NULL parameters with empty strings, since allowing NULL breaks Rust bindings, while rejecting them means apps using expressions get unexpected criticals - for example, when accessing a non-nullable string property on an object, and that object itself is NULL .

    • As mentioned in the 1.8 blog post, style-dark.css , style-hc.css and style-hc-dark.css resources are now deprecated and apps using them will get warnings on startup. Apps are encouraged to switch to a single style.css and conditionally load styles using media queries instead.

    • While not a user-visible change (hopefully!), the internal stylesheet has been refactored to use prefers-contrast media queries for high contrast styles instead of 2 conditionally loaded variants - further reducing the need on SCSS, even if not entirely replacing it just yet. (the main blocker is @extend , as well nesting and a few mixins, such as focus ring)

    Future

    A big change in works is a revamp of icon API. GTK has a new icon format that supports stateful icons with animated transitions, variable stroke weight, and many other capabilities. Currently, libadwaita doesn't make use of this, but it will in future.

    In fact, a few smaller changes are already in 1.9: all of the internal icons in libadwaita itself, as well as in the demo and docs, have been updated to use the new format.


    Thanks to the GNOME STF Team for providing the funding for this work. Also thanks to the GNOME Foundation for their support and thanks to all the contributors who made this release possible.


    Because 2026 is such an interesting period of time to live in, I feel I should explicitly say that libadwaita does not contain any AI slop, nor does allow such contributions , nor do I have any plans to change that. Same goes for all of my other projects, including this website.