Go and WebUI
Tags: 100daystooffload, go, webui, gui
Published: 2024-06-07 18:59:40

Last week Microsoft released this blog post, [An even faster Microsoft Edge](https://blogs.windows.com/msedgedev/2024/05/28/an-even-faster-microsoft-edge/), where they introduced WebUI 2.0. This has been an internal project in the Edge project, which can be summarized as a new markup-first architecture that should reduce code size and JavaScript use, giving more performance and responsiveness. 

Or simply,

> Use any web browser as GUI. With your preferred language in the backend.

The [WebUI](https://webui.me/) library is written in pure C and can be used by many different programming languages, where Go is one option.

Here is a test drive of the new library from Microsoft by using the Go language. We start out with creating the building blocks for the project.

```terminal
mkdir go-webui && cd $_

go mod init go.webui
go get github.com/webui-dev/go-webui/v2/@v2.4.0

touch main.go
code .
```

The most interesting line here is the one where we add the `go-webui` dependency to the project. With this boilerplate stuff in place we can move on to the actual code.

The program we will be writing is basic and look like this.

![the program](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rm0mrm8eh66664gh9863.png)

If you push the `Ok` button it will create a timestamp in a file. The code below is the complete program and should added to `main.go`. 

```golang
package main

import (
	"fmt"
	"os"
	"time"

	"github.com/webui-dev/go-webui/v2"
)

func main() {
	window := webui.NewWindow()

	webui.Bind(window, "OkButton", onOkButtonClicked)

	webui.Show(window, `
	<!doctype html>
	<html>
		<head>
			<meta charset="UTF-8" />
			<title>WebUI with Go</title>
			<script src="/webui.js"></script>
			<style>
				body {
					font-family: Arial, sans-serif;
					display: flex;
					flex-direction: column;
					align-items: center;
					justify-content: center;
					height: 100vh;
					margin: 0;
					background: linear-gradient(to right, #ece9e6, #ffffff);
				}
				h1 {
					color: #333;
					margin-bottom: 20px;
				}
				button {
					padding: 10px 20px;
					margin: 10px;
					border: none;
					border-radius: 5px;
					background-color: #4CAF50;
					color: white;
					font-size: 16px;
					cursor: pointer;
					transition: background-color 0.3s ease;
				}
				button:hover {
					background-color: #45a049;
				}
				button:active {
					background-color: #3e8e41;
				}
			</style>
		</head>
		<body>
			<h1>Hello World from Go!</h1>
			<button id="OkButton">Ok</button>
		</body>
	</html>`)

	webui.Wait()
}

func onOkButtonClicked(e webui.Event) string {
	fileName := "events.txt"
	line := fmt.Sprintf("%s\n", time.Now())

	file, err := os.OpenFile(fileName, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		fmt.Println("Failed to open file:", err)
		return ""
	}
	defer file.Close()

	_, err = file.WriteString(line)
	if err != nil {
		fmt.Println("Failed to write to file:", err)
		return ""
	}
	return ""
}
```

Build the application, `go build`, and then run it, `./go.webui`.

This line:

```golang
window := webui.NewWindow()
```

is creating our WebUI window object. Next step is to bind a function to the button with this line:

```golang
webui.Bind(window, "OkButton", onOkButtonClicked)
```

The, `onOkButtonClicked`, function will be invoked everytime anyone is clicking on the button.

```golang
func onOkButtonClicked(e webui.Event) string {
	fileName := "events.txt"
	line := fmt.Sprintf("%s\n", time.Now())

	file, err := os.OpenFile(fileName, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		fmt.Println("Failed to open file:", err)
		return ""
	}
	defer file.Close()

	_, err = file.WriteString(line)
	if err != nil {
		fmt.Println("Failed to write to file:", err)
		return ""
	}
	return ""
}
```

That function is responsible to append the value from `time.Now()` to the file `events.txt`. The, `Show`, function on the `window` object will show the actual GUI and which is defined as the second argument to the show function. As you can see the GUI is defined with regular CSS, HTML and JavaScript. We could have put all the HTML/CSS/JavaScript in separate files instead of inline it in the second parameter.

```golang
// Inline
webui.Show(window, "<html><script src=\"/webui.js\"> ... </html>")

// or with a file
webui.Show(window, "file.html")
```

Finally we end the `main` function with `webui.Wait()`, this will make your application run until the user closes all visible windows or when calling exit().

You can read more about WebUI in their [documentation](https://webui.me/docs/2.4/). The project seems to be moving a lot since the documentation do not exactly look like the code above, the latest version of WebUI is not 2.4.0 anymore (I believe it's 2.4.2), but I used that version since it just worked on my machine without any problems.

It will be interesting to see how this project progress in the future and if you know the web UI stuff then this might be a great library to build GUI with.

Happy hacking!