On Linux X11, NativeWebView.OnAttached() creates the GTK adapter asynchronously, after the first layout pass. The adapter never receives the current Bounds, so the X11 child window stays at the default 200×200 size and WebKit renders into a hidden corner.
Workaround: subscribe to AdapterCreated, toggle IsVisible once → triggers TryGetAdapter()?.SizeChanged(Bounds.Size).
Expected: adapter should receive current bounds immediately after creation.
Handler to fix the bug:
public sealed class AvaloniaWebViewSizeFixHandler
: Avalonia.Controls.Maui.Handlers.WebViewHandler
{
protected override void ConnectHandler(Control platformView)
{
base.ConnectHandler(platformView);
if (platformView is NativeWebView nwv)
nwv.AdapterCreated += OnNativeAdapterCreated;
}
protected override void DisconnectHandler(Control platformView)
{
if (platformView is NativeWebView nwv)
nwv.AdapterCreated -= OnNativeAdapterCreated;
base.DisconnectHandler(platformView);
}
private static void OnNativeAdapterCreated(object? sender, WebViewAdapterEventArgs e)
{
if (sender is not NativeWebView nwv) return;
// DispatcherPriority.Background: let the in-flight layout / arrange settle first
// so when we toggle IsVisible the IsVisibleProperty handler reads a fully-laid-out
// Bounds. Doing it synchronously here would race with the same layout pass that
// produced the empty Bounds in the first place.
UIThread.UIThread.Post(() =>
{
// If the page already navigated away before this tick fires, toggling
// IsVisible is a harmless no-op (NativeWebView's property handler still posts
// a SizeChanged but TryGetAdapter will return null), so no extra guard needed.
var was = nwv.IsVisible;
nwv.IsVisible = !was;
nwv.IsVisible = was;
}, DispatcherPriority.Background);
}
}
On Linux X11, NativeWebView.OnAttached() creates the GTK adapter asynchronously, after the first layout pass. The adapter never receives the current Bounds, so the X11 child window stays at the default 200×200 size and WebKit renders into a hidden corner.
Workaround: subscribe to AdapterCreated, toggle IsVisible once → triggers TryGetAdapter()?.SizeChanged(Bounds.Size).
Expected: adapter should receive current bounds immediately after creation.
Handler to fix the bug: