Launch WebviewWindow

· 6mins

Learn about Wails WebviewWindow, its configurations, and how Wails manages this window using Go and runtime APIs. In this chapter, we will set up layout for our calculator app to serve as the foundation for visualizing our app and future enhancements.

What is Webview:

I won’t delve into too much detail, as most frontend developers are already familiar with the concept of Browsers. In essence, a Webview is an embedded website rendering engine provided by the operating system, complete with its own JavaScript runtime. It’s not a full-fledged Browser.
For a deeper understanding, you can refer to Wikipedia

Webview Renderers and Runtimes:

Linux:

  • Webkit2GTK: A Linux-specific port of WebKit for embedding Webviews in applications.
  • JS Runtime: JSC

MacOS:

Windows:

Read more about Webviews in Communication in Webviews chapter

Structure of main.go

The process of launching a Wails application can be broken down into several phases:

Creating a new Application

  • This creates an app instance where you can attach multiple windows or menus.
  • Attaching Services
    • These act as an API interface for the frontend to interact with the backend.
  • Everything else when creating the app instance can be left as is.
app := application.New(application.Options{
	Name:        "learn-wails",
	Description: "A demo Calculator App",
	Services: []application.Service{
		// ... List of all the Services
	},

	// Leave the following as is,unless you know what you are doing.
	Assets: application.AssetOptions{
		Handler: application.AssetFileServerFS(assets),
	},
	Mac: application.MacOptions{
		ApplicationShouldTerminateAfterLastWindowClosed: true,
	},
})

Optional Event Handlers:

  • Attach event handlers to the app instance if needed.

Custom App Menus (Optional):

Creating a Webview Window:

  • Initialize and load the main HTML page in a new window.
app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
	Title: "Window 1",
	Mac: application.MacWindow{
		InvisibleTitleBarHeight: 50,
		Backdrop:                application.MacBackdropTranslucent,
		TitleBar:                application.MacTitleBarHiddenInset,
	},
	BackgroundColour: application.NewRGBA(0, 0, 0, 0),
	BackgroundType:   application.BackgroundTypeTransparent,
	Linux: application.LinuxWindow{
		WindowIsTranslucent: true,
	},
	URL:       "/",
	MinWidth:  800,
	MinHeight: 600,
	JS:        "console.log('preload script', document.querySelector('body'))",
	// BackgroundColour: application.NewRGB(27, 38, 54),
	// AlwaysOnTop:      true,
	// Frameless:        true,
})

// window.SetMinSize(1280, 720)
// window.SetMaxSize(2560, 1440)

Launching the Application:

The application is launched using the app.Run() API. However, the visibility of the app window can be controlled programmatically using the window.Show() and window.Hide() APIs.

  • window.Show(): Displays the app window.
  • window.Hide(): Hides the app window.

These APIs allow for flexible manipulation of the window’s visibility state based on your application’s logic or user interactions.

This chapter will focus on creating a Webview window. Other phases/APIs may be discussed in subsequent chapters.

Webview Window

A Webview Window in Wails is essentially a Go struct with custom properties, event emitters/listeners, and APIs for window management.

The WebviewWindowOptions struct is particularly important, as it defines the window’s appearance and behavior. Let’s review some of its key properties:

Key Properties of WebviewWindowOptions

AlwaysOnTop bool

  • Keeps the window above all other windows, useful for features like Quake-style terminal windows.

URL string

  • Specifies the URL or local HTML file to load. While remote hosting (via HTTP) is possible, local-first desktop apps are generally preferred. Remote capabilities can be added incrementally if needed.

Frameless bool

  • Removes the window frame and border. This is useful for curved window designs, but cross-platform support for this feature is currently limited.
  • Note that frameless windows do not support native resizing.

MinWidth, MinHeight, MaxWidth, MaxHeight int

  • Prevents resizing below specified dimensions.
  • Using window.SetMinSize or SetMaxSize feels more intuitive to me, since a user can forget to set one of these options and get confused, but the Setter APIs always require user to set both the options to restrict the window size.

Remember wails will set min width/height of the app only when both MinWidth & MinHeight options are set, i.e. != 0 The same is true for MaxWidth and MaxHeight as well.

StartState application.WindowState

  • Determines the initial state of the window (e.g., minimized, maximized).

BackgroundColour application.RGBA

  • Sets the background color of the window. For consistent cross-platform behavior, avoid using alpha transparency.
  • We can anyway override this color using CSS on html or body elements.

JS string

  • Think of it as Electron’s preload scripts.
  • JavaScript string passed to this property is loaded before the DOM is loaded (i.e before DOMContentLoaded event).

InitialPosition application.WindowStartPosition

  • Specifies the starting position of the window (e.g., centered or specific coordinates using X and Y values).

Zoom (float64)

  • Adjusts the window zoom level, useful for supporting high-resolution displays like 4K screens.

EnableDragAndDrop (bool)

  • Enables drag-and-drop functionality for file uploads or processing.

ShouldClose (func(window *WebviewWindow) bool)

  • A callback function to determine whether the application should close immediately or perform additional actions first.

Platform Specific Options:

Mac application.MacWindow
Windows application.WindowsWindow
Linux application.LinuxWindow

  • All the above options are platform specific and useful for modifying per platform window styles.

Dev options for Webview Window Options:

The following properties are particularly useful during development (and are always set to false in production builds):

  • OpenInspectorOnStartup bool: Automatically opens the developer tools when set to true.
  • DevToolsEnabled bool: Should be disabled in production builds for security. By default it is.

For more details, refer to the Wails v3 documentation or explore the source code directly.

Frontend

<script lang="ts">
   const log = (x: string) => () => {
      console.log(x);
   }
   const buttonListenerMap = {
      "fib": [log("fib"), 'a'],
      "√x": [log("square root") , 'b'],
      "^2": [log("sqaure"), 'c'],
      "/": [log("divide"), 'd'],
      "AC": [log("Reset"), 'e'],
      "7": [log("Number 7"), 'f'],
      "8": [log("Number 8"), 'g'],
      "9": [log("Number 9"), 'h'],
      "×": [log("Multiply"), 'i'],
      "C": [log("Clear"), 'j'],
      "4": [log("Number 4"), 'k'],
      "5": [log("Number 5"), 'l'],
      "6": [log("Number 6"), 'm'],
      "-": [log("Subtract"), 'n'],
      "exp": [log("Expression"), 'o'],
      "1": [log("Number 1"), 'p'],
      "2": [log("Number 2"), 'q'],
      "3": [log("Number 3"), 'r'],
      "+": [log("Addition"), 's'],
      "𝑥": [log("Variable `𝑥`"), 't'],
      "0": [log("Number 0"), 'u'],
      ".": [log("Decimal"), 'v'],
      "=": [log("Result"), 'w'],
      "𝑦": [log("Variable `𝑦`"), 'x'],
   } as Record<string, [() => void, string]>
</script>

<div class="grid">
   {#each Object.entries(buttonListenerMap) as [k, v] (k)}
      <button onclick={v[0]} style:--area={v[1]}>{k}</button>
   {/each}
</div>

<style>
   .grid {
      display: grid;
      grid-template-areas:
         "a b c d e"
         "f g h i j"
         "k l m n o"
         "p q r s t"
         "u v w s x"
      ;
      gap: 0.5rem;
      height: 100%;
   }

   button {
      font-size: 1.25rem;
      grid-area: var(--area);
      font-weight: bold;
   }
</style>
Calculator App Preview

The above screenshot is taken on a Ubuntu Desktop, and has issues with curved border on my local system.
At this stage, our goal is simply to set up a basic UI, without any functionality or logic. Those aspects will be addressed in the next chapter.
To create the layout, I have utilized CSS Grid, along with buttons and a textarea.

Refer to this Commit on the repo to check the details on the changes.

Further Reading