Home

Awesome

<p style="text-align:center"><img src="./resources/2024-05-13-demo-video.gif" width="50%" height="50%" /></p>

Spot

Build status Go Reference Go Report Card

Spot is a simple, cross-platform, reactive GUI toolkit for Go using native widgets where available. It is designed to be easy to use and to provide a consistent API across different platforms.

Example

package main

import (
	"fmt"

	"github.com/roblillack/spot"
	"github.com/roblillack/spot/ui"
)

func main() {
	ui.Init()

	spot.MountFn(func(ctx *spot.RenderContext) spot.Component {
		counter, setCounter := spot.UseState[int](ctx, 0)

		buttonTitle := "Click me!"
		if counter > 0 {
			buttonTitle = fmt.Sprintf("Clicked %d times!", counter)
		}

		return &ui.Window{
			Title:  "Hello World!",
			Width:  200,
			Height: 125,
			Children: []spot.Component{
				&ui.Button{
					X: 25, Y: 50, Width: 150, Height: 25,
					Title: buttonTitle,
					OnClick: func() {
						setCounter(counter + 1)
					},
				},
			},
		}
	})

	ui.Run()
}

Features

FAQs

What does "reactive" mean?

In the context of Spot, reactive means that the UI is automatically updated when the state of the application changes. This is achieved by re-building an immutable component tree upon state changes which can quickly be compared to the previous state in order to determine what UI controls need to be updated. In the web world, this idea is often called a "virtual DOM" and Spot actually started as an experiment to bring this concept to Go by implementing a React-like GUI library for the desktop.

By using a reactive model, the developer does not need to worry about updating the UI manually. Instead, the developer can focus on the application logic and let Spot take care of updating the UI.

What are the "native widgets" that Spot uses?

Currently, Spot uses a Cocoa backend on macOS and a FLTK-based one on all other platforms. Optionally, FLTK can be used on the Mac, too. Better support for Windows is planned for the future.

Can I implement my own hooks?

Yes, just like in React, you can implement your own hooks. Just create a function which takes a *spot.RenderContext as first argument and use this to "hook" into the Spot lifecycle by calling spot.UseState, spot.UseEffect, etc. Convention here is to prefix the function with Use….

How do I write custom components?

There are a few different ways to separate your UI into components in Spot; for some ideas, check out the custom-components example. The main way to write custom components is to create a struct that implements the spot.Component interface. This interface has a single method, Render(ctx *spot.RenderContext) spot.Component, which is called to render the component. Components created like this can be used in the same way as the built-in ones.

Look at the BlinkingButton component in the example to see how this is done.

Can I use Spot with a completely different widget library than the provided one?

Yes, you can. You just need to create some structs that implement the spot.Component interface and which take care of managing the native widgets.

Can I use spot/ui, but with a different backend than Cocoa or FLTK?

Currently, these are the only backends that are supported. But feel free to create a PR if you want to add support for another backend. *hint hint*

What's the difference between spot/ui and spot?

spot is the core package that provides the reactive model and the rendering functionality. It is backend-agnostic and can be used with any set of controls which implement the spot.Control interface.

spot/ui is a package that provides a set of pre-built cross-platform GUI controls that which can be used with spot.

What's the difference between a “component” and a “control”?

In Spot, a component is a logical unit of the application that contains business logic and state. Any component is made out of other componens and can ultimately be rendered down to a single or multiple "controls".

A control is special kind component is mounted to the UI tree and represents a visual element on the screen. Usually a control is backed by a native implementation of the GUI backend, like a button, a label, or a text input.

What do the terms ”make”, “render”, “build”, “mount”, and “update” mean in the context of Spot?

Features, Spot does not have right now

List of supported UI controls

Explanation of the status column:
❓ Not implemented / 🚧 Work in progress / ⚠️ Partially implemented / ✅ Done

NameDescriptionNative controls usedStatus
ButtonSimple button to initiate an actionFl_Button <br> NSButton
CheckboxControl offering the user a choice between two mutually exclusive optionsFl_Check_Button <br> NSButton (NSButtonTypeSwitch)
ComboBoxA combined dropdown menu with text inputComboBox <br> NSComboBoxNot started
DialCircular status controlFl_Dial <br> NSProgressIndicator (with NSCircular style)⚠️
DropdownDrop-down menu to select a single item out of multiple optionsFl_Choice <br> NSComboBox
ImageControl to display bitmap images onFl_Box <br> custom NSButton
LabelSimple, non-editable text labelFl_Box <br> NSTextField
ListBoxScrollable control which allows the user to select a single or multible items from a given listFl_Select_Browser/Fl_Multi_Browser<br> NSTableView
ProgressBarProgress bar control to visualize the progression of a long-running operationFl_Progress <br> NSProgressIndicator
SliderHorizontal slider input controlFl_Slider <br> NSSlider
SpinnerNumber input control with up/down buttonsFl_Spinner <br> NSTextField+NSStepper
TextFieldControl for single-line text inputFl_Input <br> NSTextField
TextEditorGeneral-purpose text box to edit multi-line text contentFl_Text_Editor <br> NSTextView
WindowControl representing a (top-level) window on the screenFl_Window <br> NSWindow

Potential future backends to look at