docs

Native Window Styling

Customize desktop windows with HTML chrome, native backdrop materials, transparency, and frame styles.

On this page

You can style an AppCore window beyond the standard OS frame using HTML chrome, native backdrop materials, and per-pixel transparency. The window keeps standard system behaviors like dragging, edge resizing, and window snapping.

Styling behavior varies by OS— each section notes its platform requirements and fallbacks.

Drawing Custom Chrome

Set WindowFlags::CustomChrome when creating a window to draw the title bar and caption buttons using HTML and CSS. The hosted page covers the full window surface, eliminating the need for WindowFlags::Titled.

The window retains standard frame behaviors, including edge resizing and window snapping. AppCore ignores WindowFlags::CustomChrome with a warning on popup or fullscreen windows, and when combined with WindowFlags::Borderless.

👍 Custom Chrome Walkthrough

For a step-by-step walkthrough covering HTML title bars, drag regions, caption buttons, and state changes, see Custom Window Chrome.

Custom Chrome API

Native code and the page coordinate window dragging, caption buttons, and window state through several methods, properties, and listeners:

API Description
Window::SetHitTestRegions() Registers caption drag areas and button regions in window content logical pixels. Each call replaces the full list, so register them again whenever the chrome changes layout (eg, in WindowListener::OnResize()).
app-region: drag / app-region: no-drag Marks draggable and non-draggable areas directly inside the page's CSS.
Window::SetWindowButtons() Controls which window actions are available to the user across caption buttons, title-bar double-clicks, the window menu, OS shortcuts, and snap gestures.
Window::BeginDragMove() / Window::BeginDragResize() Starts an OS window move or resize operation while you handle a left mouse-button press.
Window::window_control_bounds() / Window::SetWindowControlInset() Queries the area covered by the native window buttons and adjusts their position on macOS. macOS is the only platform that keeps native buttons floating over page content.
WindowListener::OnWindowStateChanged() / WindowListener::OnActivationChanged() Notifies you when the window maximizes, restores, or becomes active or inactive so the chrome can update its appearance.

Defining Hit-Test Regions

Hit-test regions follow several interaction and precedence rules:

Platform Differences

Custom chrome behaviors and window controls vary across desktop platforms:

Behavior Windows macOS Linux
Frame shadow and rounded corners Preserved. Preserved. No system shadow (the window manager controls corner rounding).
Right-click on a caption region Opens the system window menu. Passed to the page. Passed to the page.
Hovering a maximize region Windows 11 displays the snap layouts flyout. No effect. No effect.
Native window buttons None (the page renders its own buttons). Floats native buttons over page content. Query Window::window_control_bounds() after calling Window::SetWindowControlInset() and inside WindowListener::OnResize(). None (the page renders its own buttons).
Window::BeginDragResize() Supported. Unsupported (the OS provides its own resize edges). Supported.
Display server Any. Any. X11 or XWayland only (native Wayland is unsupported).

Applying Backdrop Materials

Call Window::SetBackdrop() to render a native OS material behind the window's content:

C++
///
/// Back the main window with the native window material, tinted by a
/// translucent dark background.
///
RefPtr<Window> window = Window::Create(App::instance()->main_monitor(), 1024,
    768, false, WindowFlags::Titled | WindowFlags::Resizable);
window->SetBackdrop(BackdropMaterial::Window);
window->SetBackgroundColor("rgba(32, 32, 32, 0.5)");

Choose the material that matches the purpose of the window. The host OS determines how each surface looks.

Material Purpose
BackdropMaterial::Window Main application windows.
BackdropMaterial::Popup Menus, dropdowns, and flyout panels. See Popups and Dialogs.
BackdropMaterial::Overlay Heads-up displays and on-screen overlays (eg, a volume indicator).
BackdropMaterial::None No material (the default).

Setting Transparency and Tint

A backdrop material shows only where content above it is transparent— both the hosted View and the web page must have transparent backgrounds.

Leaving the window background color unset displays the material untinted. Calling Window::SetBackgroundColor() with a translucent color tints the material (lower alpha values allow more of the underlying material to show through).

Backdrop Options

Pass BackdropOptions as the second argument to Window::SetBackdrop() to adjust appearance, theme, and fallback styling:

Option Description
variant Sets the visual style. BackdropVariant::Frosted creates a live blur of content behind the window, while BackdropVariant::Matte produces an opaque surface tinted by the desktop wallpaper and theme.
theme Sets BackdropTheme::Light or BackdropTheme::Dark to force a specific appearance regardless of the active OS theme.
fallback_color Specifies a solid fill color used when the platform cannot render live materials. Leaving this unset uses a color derived from the active theme.
rendition Sets BackdropRendition::Vivid for a more colorful style when using opaque window materials.

To adapt page content to the current OS theme, see Dark Mode and Color Schemes.

Handling Material Fallbacks

When an OS version or window configuration cannot render the requested material, the library substitutes the closest available appearance, falling back to a solid fill in the theme color. Windows that cannot display any material report BackdropMaterial::None.

Call Window::effective_backdrop() and Window::effective_backdrop_variant() to inspect the material and variant currently rendering on screen. To respond when the active material changes at runtime (eg, if the user toggles OS transparency settings), implement WindowListener::OnBackdropChanged().

Setting the Backdrop State

By default, a backdrop material follows the window's activation— displaying its active look while the window is active and its inactive look while it is inactive.

Call Window::SetBackdropState() with BackdropState::Active or BackdropState::Inactive to force that look regardless of activation. Not every platform honors this setting— see the platform differences below.

Platform Differences

Backdrop material behaviors and options vary across desktop platforms:

Behavior Windows macOS Linux
Setting a background color over a material Stops the material from tracking later OS theme changes. Stops the material from tracking later OS theme changes. Continues updating when the OS theme changes.
BackdropOptions::theme Sets the light or dark appearance of both the material and the title bar. Sets the light or dark appearance of both the material and the title bar. Sets the light or dark appearance of the material only.
BackdropRendition::Vivid Uses the colorful style found in apps like File Explorer. Ignored. Ignored.
Fullscreen and CPU-rendered windows Show no material and report BackdropMaterial::None. Show no material and report BackdropMaterial::None. Show at least the fallback fill and report the requested material.
Inactive look and Window::SetBackdropState() Shows the fallback fill when inactive. Titled windows on newer Windows 11 builds ignore Window::SetBackdropState() because the OS controls the inactive look. Honored. Ignored.

Creating Transparent Windows

Pass WindowFlags::Transparent during creation to enable per-pixel transparency for shaped windows or soft-edged overlays:

C++
///
/// A borderless, see-through window hosting a transparent View.
///
RefPtr<Window> window = Window::Create(App::instance()->main_monitor(), 400,
    300, false, WindowFlags::Borderless | WindowFlags::Transparent);

ViewConfig config;
config.is_transparent = true;
window->AddPanel({}, config)->view()->LoadURL("file:///shaped.html");

You can only set WindowFlags::Transparent when creating the window— it cannot be toggled later. Transparent pixels reveal underlying desktop content, allowing irregular window silhouettes and shaped cutouts.

Leaving the window background color unset leaves transparent areas completely see-through. Setting a background color with Window::SetBackgroundColor() draws that color across the window while honoring its alpha channel.

📘 Transparent Layers

Per-pixel transparency requires three layers to be transparent: the window (WindowFlags::Transparent), the hosted View (is_transparent = true in ViewConfig), and the page styles (html, body { background: transparent; }). Web pages draw on an opaque white background by default.

🚧 Mouse Input and Transparency

Mouse input isn't tested against pixel transparency— clicks over transparent pixels still reach the window rather than passing through to whatever is behind it. CPU-rendered windows on Windows are the only exception.

Platform Differences

Transparent windows behave differently depending on the host OS and renderer:

Platform and Renderer Behavior
Windows (CPU-rendered) Always borderless— frame flags are ignored with a warning. Clicks over fully transparent pixels pass through to the window beneath, and the window never receives a shadow.
Windows (GPU-rendered) The window receives mouse input across its entire rectangle. Windows start with square corners and no shadow, but rounding the window with Window::SetCornerStyle() adds the system shadow.
macOS The window receives a system shadow shaped to its visible content. Calling Window::SetCornerStyle() with CornerStyle::Square removes the shadow.

Setting the Title Bar Color

Call Window::SetCaptionColor() to tint the window's system title bar:

C++
window->SetCaptionColor("#282828");

The library automatically selects a contrasting title text color.

Setting a caption color covers any backdrop material across the title bar. Passing an unset color restores the default system appearance— allowing any backdrop material beneath to show through.

📘 Platform Support

Setting the title bar color works on Windows 11 only. macOS, Linux, and windows without a system title bar (such as custom-chrome windows) ignore the call.

Setting Corner Styles

Call Window::SetCornerStyle() to adjust the window's corner geometry:

C++
window->SetCornerStyle(CornerStyle::Rounded);

Pass CornerStyle::Rounded or CornerStyle::Square to change the corner shape, or CornerStyle::Default to follow the OS standard.

On transparent windows, the library rounds hosted web content to match the chosen corners.

Platform Differences

Corner styling and window shadows vary by platform: