Custom Window Chrome Guide
InfiniLore.InfiniFrame.Blazor provides pre-built Razor components for building custom window title bars and resize handles, typically used together with a chromeless window.
Contents
- Installation
- Enable Chromeless Mode
- Components
- Full Layout Example
- JavaScript Interop for Drag Areas
- Styling Tips
Installation
dotnet add package InfiniLore.InfiniFrame.Blazor
This package is a companion to InfiniLore.InfiniFrame.BlazorWebView or InfiniLore.InfiniFrame.WebServer.
Enable Chromeless Mode
Remove the native OS title bar so your Blazor UI is the entire window:
builder.WithInfiniFrameWindowBuilder(w => w
.SetChromeless(true)
.SetTransparent(true) // Optional: for rounded corners or glassmorphism effects
.SetSize(1280, 720)
.Center()
);
On Windows, enabling chromeless mode automatically disables UseOsDefaultLocation, UseOsDefaultSize, and Resizable. Set them explicitly if needed after calling SetChromeless.
Components
InfiniFrameWindowDragArea
Makes any area of the page draggable, acting as the window's title bar.
<InfiniFrameWindowDragArea>
<span>My Application</span>
</InfiniFrameWindowDragArea>
Place this at the top of your layout to create a custom drag region. The component handles pointer capture automatically so drag operations remain stable even when the cursor moves fast.
InfiniFrameWindowButton
A button that performs a window action (minimize, maximize, or close):
<InfiniFrameWindowButton Action="WindowAction.Minimize" />
<InfiniFrameWindowButton Action="WindowAction.Maximize" />
<InfiniFrameWindowButton Action="WindowAction.Close" />
WindowAction | Description |
|---|---|
Minimize | Minimizes the window to the taskbar |
Maximize | Maximizes or restores the window |
Close | Closes the window and exits the application |
Each button is styled via its .razor.css scoped stylesheet. Override the styles in your own CSS by targeting the component's generated class or wrapping it in a styled container.
InfiniFrameWindowResizeThumb
A drag handle for resizing the window from a specific edge or corner:
<InfiniFrameWindowResizeThumb Origin="ResizeOrigin.BottomRight" />
InfiniFrameWindowResizeThumbContainer
Renders resize thumbs for all edges and corners in a single declaration:
<InfiniFrameWindowResizeThumbContainer />
Place this at the root level of your layout so it covers the entire window perimeter.
Full Layout Example
A complete custom window chrome in a Blazor layout:
@* MainLayout.razor *@
@inherits LayoutComponentBase
<div class="window-root">
<!-- Resize handles on all edges -->
<InfiniFrameWindowResizeThumbContainer />
<!-- Custom title bar -->
<div class="titlebar">
<InfiniFrameWindowDragArea class="drag-region">
<img src="icon.png" alt="App icon" width="16" />
<span class="title">My Application</span>
</InfiniFrameWindowDragArea>
<div class="window-buttons">
<InfiniFrameWindowButton Action="WindowAction.Minimize" />
<InfiniFrameWindowButton Action="WindowAction.Maximize" />
<InfiniFrameWindowButton Action="WindowAction.Close" />
</div>
</div>
<!-- Page content -->
<main class="content">
@Body
</main>
</div>
/* MainLayout.razor.css */
.window-root {
display: flex;
flex-direction: column;
height: 100vh;
overflow: hidden;
}
.titlebar {
display: flex;
align-items: center;
height: 32px;
background: #1e1e2e;
user-select: none;
}
.drag-region {
flex: 1;
display: flex;
align-items: center;
gap: 8px;
padding: 0 12px;
height: 100%;
}
.window-buttons {
display: flex;
height: 100%;
}
.content {
flex: 1;
overflow: auto;
}
JavaScript Interop for Drag Areas
InfiniLore.InfiniFrame.Js is used internally by the drag and resize components to call setPointerCapture on the underlying DOM element. This ensures drag operations continue even when the pointer leaves the element boundary.
If you are building your own drag components, you can use IInfiniFrameJs directly:
@inject IInfiniFrameJs InfiniJs
<div @ref="dragRef" @onpointerdown="OnPointerDown">...</div>
@code {
ElementReference dragRef;
async Task OnPointerDown(PointerEventArgs e) {
await InfiniJs.SetPointerCaptureAsync(dragRef, e.PointerId, CancellationToken.None);
}
}
See the JavaScript Interop Guide for full details.
Styling Tips
- The resize thumbs are transparent by default; they only respond to pointer events at the window edge.
- On Windows with
SetTransparent(true), your CSSbackground: transparentwill show through to the desktop, enabling acrylic or mica-style effects via the CSS backdrop. - Double-clicking on a
InfiniFrameWindowDragAreadoes not automatically maximize. Handle@ondblclickyourself if you want that behavior:
@inject IInfiniFrameWindow Window
<InfiniFrameWindowDragArea @ondblclick="ToggleMaximize">
...
</InfiniFrameWindowDragArea>
@code {
void ToggleMaximize() => Window.ToggleMaximized();
}