Skip to content

Window Basics

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.

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.

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

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:

OptionTypeDescription
TitlestringWindow title
WidthintWindow width in pixels
HeightintWindow height in pixels
XintX position (from left)
YintY position (from top)
AlwaysOnTopboolKeep window above others
FramelessboolRemove title bar and borders
HiddenboolStart hidden
MinWidthintMinimum width
MinHeightintMinimum height
MaxWidthintMaximum width
MaxHeightintMaximum height

See Window Options for complete list.

Give windows names for easy retrieval:

window := app.Window.NewWithOptions(application.WebviewWindowOptions{
Name: "main-window",
Title: "Main Application",
})
// Later, find it by name
mainWindow := app.GetWindowByName("main-window")
if mainWindow != nil {
mainWindow.Show()
}

Use cases:

  • Multiple windows (main, settings, about)
  • Finding windows from different parts of your code
  • Window communication
// 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)
// 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
// 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 ←→ Fullscreen
// Set title
window.SetTitle("My Application - Document.txt")
// Set background colour
window.SetBackgroundColour(0, 0, 0, 255) // RGBA
// Set always on top
window.SetAlwaysOnTop(true)
// Set resizable
window.SetResizable(false)
// Close window
window.Close()
// Destroy window (force close)
window.Destroy()

Difference:

  • Close() - Triggers close event, can be cancelled
  • Destroy() - Immediate destruction, cannot be cancelled
window := app.GetWindowByName("settings")
if window != nil {
window.Show()
}

Every window has a unique ID:

id := window.ID()
fmt.Printf("Window ID: %d\n", id)
// Find by ID
foundWindow := app.GetWindowByID(id)

Get the currently focused window:

current := app.Window.Current()
if current != nil {
current.SetTitle("Active Window")
}

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())
}
app.OnWindowCreation(func(window *application.WebviewWindow) {
fmt.Printf("Window created: %s\n", window.Name())
// Configure new windows
window.SetMinSize(400, 300)
})
window.OnClose(func() bool {
// Return false to cancel close
// Return true to allow close
if hasUnsavedChanges() {
result := showConfirmdialog("Unsaved changes. Close anyway?")
return result == "yes"
}
return true
})

Important: OnClose only works for user-initiated closes (clicking X button). It doesn’t prevent window.Destroy().

window.OnDestroy(func() {
fmt.Println("Window destroyed")
// Cleanup resources
})
// 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()

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.WailsEvent) {
data := event.Data.(map[string]interface{})
value := data["value"].(int)
fmt.Printf("Received: %d\n", value)
})

See Events for more.

// Create child window
childWindow := app.Window.NewWithOptions(application.WebviewWindowOptions{
Title: "Child Window",
Parent: mainWindow, // Set parent
})

Behaviour:

  • Child closes when parent closes
  • Child stays above parent (on some platforms)
  • Child minimises with parent (on some platforms)

Platform support:

  • macOS: Full support
  • Windows: Partial support
  • Linux: Varies by desktop environment

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()
// Set window icon
window.SetIcon(iconBytes)

Snap Assist: Shows Windows 11 snap layout options for the window.

Taskbar flashing: Useful for notifications when window is minimised.

// 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()
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.SetFocus()
}
window.OnClose(func() bool {
if hasUnsavedChanges() {
// Show dialog
result := showConfirmdialog("Unsaved changes. Close anyway?")
return result == "yes"
}
return true
})
  • 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 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

Possible causes:

  1. Window created as hidden
  2. Window off-screen
  3. Window behind other windows

Solution:

window.Show()
window.Center()
window.SetFocus()

Cause: DPI scaling on Windows/Linux

Solution:

// Wails handles DPI automatically
// Just use logical pixels
window.SetSize(800, 600)

Cause: Application exits when last window closes

Solution:

app := application.New(application.Options{
Mac: application.MacOptions{
ApplicationShouldTerminateAfterLastWindowClosed: false,
},
})

Window Options

Complete reference for all window options.

Learn More →

Multiple Windows

Patterns for multi-window applications.

Learn More →


Questions? Ask in Discord or check the window examples.