Skip to content

feat(desktop): draw an integrated title bar on Windows#2504

Open
al3rez wants to merge 1 commit into
block:mainfrom
al3rez:windows-frameless-titlebar
Open

feat(desktop): draw an integrated title bar on Windows#2504
al3rez wants to merge 1 commit into
block:mainfrom
al3rez:windows-frameless-titlebar

Conversation

@al3rez

@al3rez al3rez commented Jul 23, 2026

Copy link
Copy Markdown

Why

macOS runs the main window with titleBarStyle: "Overlay", so AppTopChrome covers the top edge and the whole window reads as one surface. Windows had nothing equivalent. It drew the system caption bar directly above our sidebar-colored chrome, and the seam showed. No Tauri setting tints that bar, so the only way to close the gap is to stop Windows drawing it.

What this does

Decorations go off once the webview is ready, and the web chrome takes the full top edge. set_shadow(true) puts back the drop shadow and rounded corners a window loses when it goes undecorated.

Windows has no traffic lights, so the app draws minimize, maximize/restore and close itself. They follow the Fluent 46x32 metrics and sit flush against the edge, and the chrome drops its right padding while they're showing. They're sized in px rather than rem for the same reason the macOS traffic lights are: Ctrl +/- text zoom shouldn't resize them.

Dragging already worked, since the chrome carries data-tauri-drag-region. The buttons opt out of it so their clicks land.

Result

Buzz on Windows with the integrated title bar

The sidebar color runs straight from the window edge through the chrome, with the caption buttons drawn into that same surface.

Testing

Windows 11 (26100), WebView2. Confirmed in the DOM that the controls land at x:874 y:0, 138x40, visible, and that a hit test on their center returns svg -> button -> controls -> chrome(z-45) with nothing sitting on top of them. pnpm typecheck, biome check and cargo check on the Tauri crate all pass.

What doesn't work yet

Hovering the maximize button doesn't open the Windows 11 snap-layout flyout. That needs WM_NCHITTEST to answer HTMAXBUTTON, which isn't reachable from the webview and would take a native window-proc hook. Win+arrow and dragging to a screen edge still snap.

One bit worth a second opinion: isWindowsPlatform() checks navigator.platform (WebView2 reports Win32) and falls back to the user agent. Belt and braces, but if that check ever comes back false on an undecorated window you get a window with no close button, so I didn't want it resting on a single deprecated API.

@al3rez
al3rez requested a review from a team as a code owner July 23, 2026 11:56
@al3rez
al3rez force-pushed the windows-frameless-titlebar branch from 5b785ea to 4ac3108 Compare July 23, 2026 11:59
macOS runs the main window with `titleBarStyle: "Overlay"`, so `AppTopChrome`
covers the top edge and the window looks like one surface. Windows had nothing
equivalent. It drew the system caption bar directly above our sidebar-colored
chrome, and the seam showed. No Tauri setting tints that bar, so the only way
to close the gap is to stop Windows drawing it.

Turn decorations off once the webview is ready and let the web chrome own the
whole top edge. `set_shadow(true)` puts back the drop shadow and rounded
corners a window loses when it goes undecorated.

Windows has no traffic lights, so the app draws minimize, maximize/restore and
close itself. They follow the Fluent 46x32 metrics, sit flush against the edge,
and the chrome drops its right padding while they are showing. They are sized
in px rather than rem for the same reason the macOS traffic lights are: Ctrl +/-
text zoom should not resize them.

Dragging already worked, since the chrome carries `data-tauri-drag-region`. The
buttons opt out of it so their clicks land.

Still missing: hovering maximize does not open the Windows 11 snap-layout
flyout. That needs WM_NCHITTEST to answer HTMAXBUTTON, which the webview cannot
reach. Win+arrow and dragging to a screen edge still snap.

Signed-off-by: Alireza Bashiri <al3rez@gmail.com>
@al3rez
al3rez force-pushed the windows-frameless-titlebar branch from 4ac3108 to 9f39d6f Compare July 23, 2026 12:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant