Skip to content

Windows Sub Window

Former Not Wannabe Lord Paramount of the Wkwkland edited this page May 24, 2026 · 1 revision

Sub-window blank on Windows — Root cause & fix

Problem

Sub-windows (opened via open_new_window) appeared as blank/white windows on Windows, while working correctly on macOS and Linux.

Root cause

On Windows, Tauri uses the WebView2 control, which has an asynchronous initialization process. When WebviewWindowBuilder::build() is called:

  1. It creates the native HWND (the blank window you see).
  2. It then schedules WebView2 initialization, which requires the Windows message pump (event loop) to be running on the main thread.

The bug was that open_new_window was declared as a synchronous Tauri command (pub fn — blocks the main thread).

Main thread:  [--- sync command running --->  waits for build() ...]
Message pump: [   blocked   ]

WebView2 init needs the message pump → deadlock → window stays blank forever

On macOS (WKWebView) and Linux (WebKitGTK), the webview implementations don't have this synchronous-creation limitation, so sub-windows worked fine there.

Fix — 3 changes

1. Make Tauri commands async

src-tauri/src/commands.rs (lines 354–357, 360–361)

// Before (sync — blocks main thread):
#[tauri::command]
pub fn open_new_window(...) { ... }

// After (async — runs on thread pool, main thread stays free):
#[tauri::command]
pub async fn open_new_window(...) { ... }

Async commands run on Tauri's async thread pool, so the main thread's message pump keeps running and WebView2 can initialize properly.

2. Wrap window creation in spawn in sync contexts

src-tauri/src/main.rs (menu event handler, lines 385–432)

The on_menu_event callback is inherently synchronous. We wrapped each open_new_window_internal call in tauri::async_runtime::spawn to move the blocking work off the main thread:

// Before — called directly from sync callback:
open_new_window_internal(&handle, ...);

// After — spawned onto async runtime:
let h = handle.clone();
tauri::async_runtime::spawn(async move {
    open_new_window_internal(&h, ...);
});

Same pattern applied to trigger_menu_action command in commands.rs.

3. Fix CSS background mismatch

src/styles.css (line 11)

/* Before — transparent HTML over non-transparent window = white background */
html, body, #root { background: transparent !important; }

/* After — dark background for non-transparent sub-windows */
html, body, #root { background: #09090b; }

The main window has "transparent": true in tauri.conf.json (glass effect). Sub-windows created via WebviewWindowBuilder default to transparent: false. With background: transparent in CSS, sub-windows showed the default WebView2 white background behind the semi-transparent dark UI, causing visual artifacts.

Files changed

File Change
src-tauri/src/commands.rs Made open_new_window and trigger_menu_action async; spawned window creation in async tasks
src-tauri/src/main.rs Wrapped menu event handler window creation in tauri::async_runtime::spawn
src/styles.css Changed background: transparentbackground: #09090b