Window Basics
Window Management
Wails provides a unified window management API that works across all platforms. Create windows, control their behaviour, and manage multiple windows with full control over creation, appearance, behaviour, and lifecycle.
Quick Start
package main
import "github.com/wailsapp/wails/v3/pkg/application"
func main() {
app := application.New(application.Options{
Name: "My App",
})
// Create a window
window := app.Window.New()
// Configure it
window.SetTitle("Hello Wails")
window.SetSize(800, 600)
window.Center()
// Show it
window.Show()
app.Run()
}That’s it! You have a cross-platform window.
Creating Windows
Basic Window
The simplest way to create a window:
window := app.Window.New()What you get:
- Default size (800x600)
- Default title (application name)
- WebView ready for your frontend
- Platform-native appearance
Window with Options
Create a window with custom configuration:
window := app.Window.NewWithOptions(application.WebviewWindowOptions{
Title: "My Application",
Width: 1200,
Height: 800,
X: 100, // Position from left
Y: 100, // Position from top
AlwaysOnTop: false,
Frameless: false,
Hidden: false,
MinWidth: 400,
MinHeight: 300,
MaxWidth: 1920,
MaxHeight: 1080,
})Common options:
| Option | Type | Description |
|---|---|---|
Title |
string |
Window title |
Width |
int |
Window width in pixels |
Height |
int |
Window height in pixels |
X |
int |
X position (from left) |
Y |
int |
Y position (from top) |
AlwaysOnTop |
bool |
Keep window above others |
Frameless |
bool |
Remove title bar and borders |
Hidden |
bool |
Start hidden |
MinWidth |
int |
Minimum width |
MinHeight |
int |
Minimum height |
MaxWidth |
int |
Maximum width |
MaxHeight |
int |
Maximum height |
See Window Options for complete list.
Named Windows
Give windows names for easy retrieval:
window := app.Window.NewWithOptions(application.WebviewWindowOptions{
Name: "main-window",
Title: "Main Application",
})
// Later, find it by name
if mainWindow, ok := app.Window.GetByName("main-window"); ok {
mainWindow.Show()
}Use cases:
- Multiple windows (main, settings, about)
- Finding windows from different parts of your code
- Window communication
Controlling Windows
Show and Hide
// Show window
window.Show()
// Hide window
window.Hide()
// Check if visible
if window.IsVisible() {
fmt.Println("Window is visible")
}Use cases:
- Splash screens (show, then hide)
- Settings windows (hide when not needed)
- Popup windows (show on demand)
Position and Size
// Set size
window.SetSize(1024, 768)
// Set position
window.SetPosition(100, 100)
// Centre on screen
window.Center()
// Get current size
width, height := window.Size()
// Get current position
x, y := window.Position()Coordinate system:
- (0, 0) is top-left of primary screen
- Positive X goes right
- Positive Y goes down
Window State
// Minimise
window.Minimise()
// Maximise
window.Maximise()
// Fullscreen
window.Fullscreen()
// Restore to normal
window.Restore()
// Check state
if window.IsMinimised() {
fmt.Println("Window is minimised")
}
if window.IsMaximised() {
fmt.Println("Window is maximised")
}
if window.IsFullscreen() {
fmt.Println("Window is fullscreen")
}State transitions:
Normal ←→ Minimised
Normal ←→ Maximised
Normal ←→ FullscreenTitle and Appearance
// Set title
window.SetTitle("My Application - Document.txt")
// Set background colour — RGBA value (helper for RGB)
window.SetBackgroundColour(application.NewRGBA(0, 0, 0, 255))
// Set always on top
window.SetAlwaysOnTop(true)
// Set resizable
window.SetResizable(false)Closing Windows
// Close window — dispatches WindowClosing; a RegisterHook can call e.Cancel().
window.Close()There is no window.Destroy() method in v3 — use Close() and either listen with OnWindowEvent (cannot cancel) or hook with RegisterHook (can call e.Cancel() to keep the window open).
Finding Windows
By Name
if window, ok := app.Window.GetByName("settings"); ok {
window.Show()
}By ID
Every window has a unique ID:
id := window.ID()
fmt.Printf("Window ID: %d\n", id)
// Find by ID
if found, ok := app.Window.GetByID(id); ok {
found.Focus()
}Current Window
Get the currently focused window:
current := app.Window.Current()
if current != nil {
current.SetTitle("Active Window")
}All Windows
Get all windows:
windows := app.Window.GetAll()
fmt.Printf("Total windows: %d\n", len(windows))
for _, w := range windows {
fmt.Printf("Window: %s (ID: %d)\n", w.Name(), w.ID())
}Window Lifecycle
Creation
app.Window.OnCreate(func(window application.Window) {
fmt.Printf("Window created: %s\n", window.Name())
// Configure new windows
window.SetMinSize(400, 300)
})Closing
To prevent a window from closing, use RegisterHook with the WindowClosing event:
window.RegisterHook(events.Common.WindowClosing, func(event *application.WindowEvent) {
if hasUnsavedChanges() {
// Ask user for confirmation
result := showConfirmDialog("Unsaved changes. Close anyway?")
if result != "yes" {
// Cancel the close event
event.Cancel()
}
}
})Important: RegisterHook intercepts the close event before it happens. Call event.Cancel() to prevent the window from closing. This works for user-initiated closes (clicking X button).
Destruction
To perform cleanup when a window closes, use OnWindowEvent with the WindowClosing event:
window.OnWindowEvent(events.Common.WindowClosing, func(event *application.WindowEvent) {
fmt.Println("Window is closing")
// Cleanup resources
})Multiple Windows
Creating Multiple Windows
// Main window
mainWindow := app.Window.NewWithOptions(application.WebviewWindowOptions{
Name: "main",
Title: "Main Application",
Width: 1200,
Height: 800,
})
// Settings window
settingsWindow := app.Window.NewWithOptions(application.WebviewWindowOptions{
Name: "settings",
Title: "Settings",
Width: 600,
Height: 400,
Hidden: true, // Start hidden
})
// Show settings when needed
settingsWindow.Show()Window Communication
Windows can communicate via events:
// In main window
app.Event.Emit("data-updated", map[string]interface{}{
"value": 42,
})
// In settings window
app.Event.On("data-updated", func(event *application.CustomEvent) {
data := event.Data.(map[string]interface{})
value := data["value"].(int)
fmt.Printf("Received: %d\n", value)
})See Events for more.
Parent-Child Windows
WebviewWindowOptions has no Parent field. Create the child as a normal window and attach it to a parent as a sheet modal:
// Create child window
childWindow := app.Window.NewWithOptions(application.WebviewWindowOptions{
Title: "Child Window",
})
// Attach to the parent — presents as a sheet on macOS.
mainWindow.AttachModal(childWindow)Behaviour:
- Child stays above parent.
- Child is modal — blocks interaction with the parent.
Platform support:
- macOS: Full support (presents as a sheet).
- Windows: Not supported.
- Linux: Not supported.
Platform-Specific Features
Windows-specific features:
// Flash taskbar button
window.Flash(true) // Start flashing
window.Flash(false) // Stop flashing
// Trigger Windows 11 Snap Assist (Win+Z)
window.SnapAssist()There is no per-window SetIcon — the application icon is set on the app via app.SetIcon([]byte) (or for a Linux-specific window icon, the application.LinuxWindow.Icon field at window creation).
Snap Assist: Shows Windows 11 snap layout options through the system shortcut path. For a custom HTML maximize button with native hover Snap Layouts, use Native Non-Client Regions on Windows instead.
Taskbar flashing: Useful for notifications when window is minimised.
macOS-specific features:
// Transparent title bar
window := app.Window.NewWithOptions(application.WebviewWindowOptions{
Mac: application.MacWindow{
TitleBar: application.MacTitleBar{
AppearsTransparent: true,
},
Backdrop: application.MacBackdropTranslucent,
},
})Backdrop types:
MacBackdropNormal- Standard windowMacBackdropTranslucent- Translucent backgroundMacBackdropTransparent- Fully transparent
Collection behavior: Control how windows behave across Spaces:
MacWindowCollectionBehaviorCanJoinAllSpaces- Visible on all SpacesMacWindowCollectionBehaviorFullScreenAuxiliary- Can overlay fullscreen apps
Native fullscreen: macOS fullscreen creates a new Space (virtual desktop).
Linux-specific features:
// Set window icon (per-window struct is LinuxWindow, not the app-level LinuxOptions)
window := app.Window.NewWithOptions(application.WebviewWindowOptions{
Linux: application.LinuxWindow{
Icon: iconBytes,
},
})Desktop environment notes:
- GNOME: Full support
- KDE Plasma: Full support
- XFCE: Partial support
- Others: Varies
Tiling window managers (Hyprland, Sway, i3, etc.):
Minimise()andMaximise()may not work as expected - the WM controls window geometrySetSize()andSetPosition()requests are advisory and may be ignoredFullscreen()typically works as expected- Some WMs don’t support always-on-top
Common Patterns
Splash Screen
// Create splash screen
splash := app.Window.NewWithOptions(application.WebviewWindowOptions{
Title: "Loading...",
Width: 400,
Height: 300,
Frameless: true,
AlwaysOnTop: true,
})
// Show splash
splash.Show()
// Initialise application
time.Sleep(2 * time.Second)
// Hide splash, show main window
splash.Close()
mainWindow.Show()Settings Window
var settingsWindow *application.WebviewWindow
func showSettings() {
if settingsWindow == nil {
settingsWindow = app.Window.NewWithOptions(application.WebviewWindowOptions{
Name: "settings",
Title: "Settings",
Width: 600,
Height: 400,
})
}
settingsWindow.Show()
settingsWindow.Focus()
}Confirm Before Close
window.RegisterHook(events.Common.WindowClosing, func(event *application.WindowEvent) {
if hasUnsavedChanges() {
// Show dialog
result := showConfirmDialog("Unsaved changes. Close anyway?")
if result != "yes" {
// Cancel the close event
event.Cancel()
}
}
})Best Practices
✅ Do
- Name important windows - Easier to find later
- Set minimum size - Prevent unusable layouts
- Centre windows - Better UX than random position
- Handle close events - Prevent data loss
- Test on all platforms - Behaviour varies
- Use appropriate sizes - Consider different screen sizes
❌ Don’t
- Don’t create too many windows - Confusing for users
- Don’t forget to close windows - Memory leaks
- Don’t hardcode positions - Different screen sizes
- Don’t ignore platform differences - Test thoroughly
- Don’t block the UI thread - Use goroutines for long operations
Troubleshooting
Window Not Showing
Possible causes:
- Window created as hidden
- Window off-screen
- Window behind other windows
Solution:
window.Show()
window.Center()
window.Focus()Window Wrong Size
Cause: DPI scaling on Windows/Linux
Solution:
// Wails handles DPI automatically
// Just use logical pixels
window.SetSize(800, 600)Window Closes Immediately
Cause: Application exits when last window closes
Solution:
app := application.New(application.Options{
Mac: application.MacOptions{
ApplicationShouldTerminateAfterLastWindowClosed: false,
},
})Next Steps
Complete reference for all window options.
Patterns for multi-window applications.
Create custom window chrome.
Handle window lifecycle events.
Questions? Ask in Discord or check the window examples.