Skip to content

Sidebar exclusiveZone and visual width animations desync, causing a visible gap on close (Hyprland) #866

Description

@AugustoMegener

Description

I'm building a custom Hyprland shell with Quickshell and ran into a rendering issue I can't fully solve on the QML side. I'm opening this issue because I believe the root cause might be in how exclusiveZone updates are applied to the compositor relative to the actual window content render.

The setup

I have a PanelWindow acting as a collapsible sidebar. It animates between a "collapsed" width and an "expanded" width using a NumberAnimation on a single shared property, which then drives both exclusiveZone and the visual Rectangle width that fills the panel. The idea was that since both values come from the same animated property, they should stay perfectly in sync frame by frame.

The problem

When you open the sidebar, everything looks normal at high speed, but at low speed the gap appears.

When closing the sidebar, at fast speed the background immediately changes to the target size, leaving a gap until the exclusive zone shrinks to the same point. At slow speed, the same opening behavior occurs.

This is demonstrated in the attached video.

Current code

import Quickshell
import Quickshell.Wayland
import QtQuick
import "../Theme"
import "../SideBar"

PanelWindow {
    id: sidebar
    required property string side
    WlrLayershell.layer: WlrLayershell.Layer.Bottom
    aboveWindows: false
    color: "transparent"
    anchors {
        top: true
        bottom: true
        left: side == "left"
        right: side == "right"
    }

    property int targetZone: side == "left"
        ? (SideBarState.leftOpen ? SideBarState.leftWidth : 45)
        : (SideBarState.rightOpen ? SideBarState.rightWidth : 0)
    property int sidebarWidth: targetZone

    exclusiveZone: sidebarWidth
    implicitWidth: sidebarWidth

    onTargetZoneChanged: anim.restart()

    Component.onCompleted: {
        sidebarWidth = targetZone
    }

    NumberAnimation {
        id: anim
        target: sidebar
        property: "sidebarWidth"
        from: sidebar.sidebarWidth
        to: sidebar.targetZone
        duration: 30
    }

    mask: Region { item: content }

    Rectangle {
        id: content
        anchors.top: parent.top
        anchors.bottom: parent.bottom
        anchors.left: sidebar.side == "left" ? parent.left : undefined
        anchors.right: sidebar.side == "right" ? parent.right : undefined
        color: "#2b2622"
        width: sidebar.sidebarWidth
    }
}

What I've already tried

  • Animating exclusiveZone and the content Rectangle.width separately with two NumberAnimations in a ParallelAnimation — same desync.
  • Using Behavior on width on the Rectangle and letting exclusiveZone follow via onWidthChanged — same issue.
  • Binding both properties to a single shared animated property (current code above) — issue persists specifically on close.

Environment

  • Hyprland: 0.54.3
  • Quickshell: 0.3.0 (Official-Nix-Flake)

Repo

https://github.com/AugustoMegener/primary-shell/tree/main/qml

Video demo

2026-06-18.10-59-37.mp4

Any insight into whether this is expected behavior on the Hyprland side would be super helpful. Happy to provide more repro steps or test patches if needed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions