Skip to content

What's New in Wails v3 Alpha#

Wails v3 Alpha moves from the v2's single-window, declarative API to a procedural one. This intuitive API makes code development easier, boosts readability, and unlocks complex multi-window apps. Wails v3 Alpha isn't just an improvement on past versions - it reimagines desktop application development capabilities with Go and modern web technologies.

Multiple Windows#

It's now possible to create multiple windows and configure each one independently.

package main

import (
        _ "embed"
        "log"

        "github.com/wailsapp/wails/v3/pkg/application"
)

//go:embed assets/*
var assets embed.FS

func main() {

        app := application.New(application.Options{
                Name:        "Multi Window Demo",
                Assets: application.AssetOptions{
                        Handler: application.AssetFileServerFS(assets),
                },
        })

        window1 := app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
                Title:  "Window 1",
        })

        window2 := app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
                Title:  "Window 2",
        })

        // load the embedded html from the embed.FS
        window1.SetURL("/")
        window1.Center()

        // Load an external URL
        window2.SetURL("https://wails.app")

        err := app.Run()

        if err != nil {
                log.Fatal(err.Error())
        }
}

Systrays#

Systrays allow you to add an icon in the system tray area of your desktop and have the following features:

  • Attach window (the window will be centered to the systray icon)
  • Full menu support
  • Light/Dark mode icons
package main

import (
    _ "embed"
    "log"
    "runtime"

    "github.com/wailsapp/wails/v3/pkg/application"
    "github.com/wailsapp/wails/v3/pkg/icons"
)

func main() {
    app := application.New(application.Options{
        Name:        "Systray Demo",
        Mac: application.MacOptions{
            ActivationPolicy: application.ActivationPolicyAccessory,
        },
    })

    window := app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
        Width:       500,
        Height:      800,
        Frameless:   true,
        AlwaysOnTop: true,
        Hidden:      true,
        Windows: application.WindowsWindow{
            HiddenOnTaskbar: true,
        },
    })

    systemTray := app.NewSystemTray()

    // Support for template icons on macOS
    if runtime.GOOS == "darwin" {
        systemTray.SetTemplateIcon(icons.SystrayMacTemplate)
    } else {
        // Support for light/dark mode icons
        systemTray.SetDarkModeIcon(icons.SystrayDark)
        systemTray.SetIcon(icons.SystrayLight)
    }

    // Support for menu
    myMenu := app.NewMenu()
    myMenu.Add("Hello World!").OnClick(func(_ *application.Context) {
        println("Hello World!")
    })
    systemTray.SetMenu(myMenu)

    // This will center the window to the systray icon with a 5px offset
    // It will automatically be shown when the systray icon is clicked
    // and hidden when the window loses focus
    systemTray.AttachWindow(window).WindowOffset(5)

    err := app.Run()
    if err != nil {
        log.Fatal(err)
    }
}

Plugins#

Plugins allow you to extend the functionality of the Wails system. Not only can plugin methods be used in Go, but also called from Javascript. Included plugins:

  • kvstore - A key/value store
  • browser - open links in a browser
  • log - custom logger
  • oauth - handles oauth authentication and supports 60 providers
  • single_instance - only allow one copy of your app to be run
  • sqlite - add a sqlite db to your app. Uses the modernc pure go library
  • start_at_login - Register/Unregister your application to start at login

Improved bindings generation#

v3 uses a new static analyser to generate bindings. This makes it extremely fast and maintains comments and parameter names in your bindings. By default, bindings are generated with calls using IDs instead of strings. This provides a performance boost and allows for using obfuscation tools such as garble.

Bindings are generated by simply running wails3 generate bindings in the project directory.

// @ts-check
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT

import { main } from "./models";

window.go = window.go || {};
window.go.main = {
  GreetService: {
    /**
     * GreetService.Greet
     * Greet greets a person
     * @param name {string}
     * @returns {Promise<string>}
     **/
    Greet: function (name) {
      wails.CallByID(1411160069, ...Array.prototype.slice.call(arguments, 0));
    },

    /**
     * GreetService.GreetPerson
     * GreetPerson greets a person
     * @param person {main.Person}
     * @returns {Promise<string>}
     **/
    GreetPerson: function (person) {
      wails.CallByID(4021313248, ...Array.prototype.slice.call(arguments, 0));
    },
  },
};

Improved build system#

In v2, the build system was completely opaque and hard to customise. In v3, it's possible to build everything using standard Go tooling.

All the heavy lifting that the v2 build system did, such as icon generation, have been added as tool commands in the CLI. We have incorporated Taskfile into the CLI to orchestrate these calls to bring the same developer experience as v2. However, this approach brings the ultimate balance of flexibility and ease of use as you can now customise the build process to your needs.

You can even use make if that's your thing!

Snippet from Taskfile.yml
build:darwin:
  summary: Builds the application
  platforms:
    - darwin
  cmds:
    - task: pre-build
    - task: build-frontend
    - go build -gcflags=all="-N -l" -o bin/{{.APP_NAME}}
    - task: post-build
  env:
    CGO_CFLAGS: "-mmacosx-version-min=10.13"
    CGO_LDFLAGS: "-mmacosx-version-min=10.13"
    MACOSX_DEPLOYMENT_TARGET: "10.13"

Improved events#

Events are now emitted for a lot of the runtime operations, allowing you to hook into application/system events. Cross-platform (common) events are also emitted where there are common platform events, allowing you to write the same event handling methods cross platform.

Event hooks can also be registered. These are like the On method but are synchronous and allow you to cancel the event. An example of this would be to show a confirmation dialog before closing a window.

package main

import (
    _ "embed"
    "log"
    "time"

    "github.com/wailsapp/wails/v3/pkg/application"
    "github.com/wailsapp/wails/v3/pkg/events"
)

//go:embed assets
var assets embed.FS

func main() {

    app := application.New(application.Options{
        Name:        "Events Demo",
        Description: "A demo of the Events API",
        Assets: application.AssetOptions{
            Handler: application.AssetFileServerFS(assets),
        },
        Mac: application.MacOptions{
            ApplicationShouldTerminateAfterLastWindowClosed: true,
        },
    })

    // Custom event handling
    app.Events.On("myevent", func(e *application.WailsEvent) {
        log.Printf("[Go] WailsEvent received: %+v\n", e)
    })

    // OS specific application events
    app.On(events.Mac.ApplicationDidFinishLaunching, func(event *application.Event) {
        println("events.Mac.ApplicationDidFinishLaunching fired!")
    })

    // Platform agnostic events
    app.On(events.Common.ApplicationStarted, func(event *application.Event) {
        println("events.Common.ApplicationStarted fired!")
    })

    win1 := app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
        Title: "Takes 3 attempts to close me!",
    })

    var countdown = 3

    // Register a hook to cancel the window closing
    win1.RegisterHook(events.Common.WindowClosing, func(e *application.WindowEvent) {
        countdown--
        if countdown == 0 {
            println("Closing!")
            return
        }
        println("Nope! Not closing!")
        e.Cancel()
    })

    win1.On(events.Common.WindowFocus, func(e *application.WindowEvent) {
        println("[Event] Window focus!")
    })

    err := app.Run()

    if err != nil {
        log.Fatal(err.Error())
    }
}

Wails Markup Language (wml)#

An experimental feature to call runtime methods using plain html, similar to htmx.

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Wails ML Demo</title>
  </head>
  <body style="margin-top:50px; color: white; background-color: #191919">
    <h2>Wails ML Demo</h2>
    <p>This application contains no Javascript!</p>
    <button wml-event="button-pressed">Press me!</button>
    <button wml-event="delete-things" wml-confirm="Are you sure?">
      Delete all the things!
    </button>
    <button wml-window="Close" wml-confirm="Are you sure?">
      Close the Window?
    </button>
    <button wml-window="Center">Center</button>
    <button wml-window="Minimise">Minimise</button>
    <button wml-window="Maximise">Maximise</button>
    <button wml-window="UnMaximise">UnMaximise</button>
    <button wml-window="Fullscreen">Fullscreen</button>
    <button wml-window="UnFullscreen">UnFullscreen</button>
    <button wml-window="Restore">Restore</button>
    <div
      style="width: 200px; height: 200px; border: 2px solid white;"
      wml-event="hover"
      wml-trigger="mouseover"
    >
      Hover over me
    </div>
  </body>
</html>

Examples#

There are more examples available in the examples directory. Check them out!