Declarative Syntax
Intro
The go-app declarative syntax is to customize components’ look.
It uses a chaining mechanism made from the Go programming language syntax that allows composing HTML elements and components in order to craft beautiful and usable UIs.
Here is an example where HTML elements are used to display a title and a paragraph:
func (c *myCompo) Render() app.UI {
return app.Div().Body(
app.H1().
Class("title").
Text("Build a GUI with Go"),
app.P().
Class("text").
Text("Just because Go and this package are really awesome!"),
)
}
HTML Elements
Go-app provides interfaces for each standard HTML element. Those interfaces describe setters for attributes and event handlers.
Here is a simplified version of the interface for a <div>:
type HTMLDiv interface {
// Attributes:
Body(children ...UI) HTMLDiv
Class(v string) HTMLDiv
ID(v string) HTMLDiv
Style(k, v string) HTMLDiv
// Event handlers:
OnClick(h EventHandler, scope ...interface{}) HTMLDiv
OnKeyPress(h EventHandler, scope ...interface{}) HTMLDiv
OnMouseOver(h EventHandler, scope ...interface{}) HTMLDiv
}
Create
An HTML element is created by calling a function named after its name. The example below shows how to create a <div>:
func (c *myCompo) Render() app.UI {
return app.Div()
}
Standard Elements
A standard HTML element is an element that can contain other UI elements. Other HTML elements, texts, and components are nested by using the Body()
method:
func (c *myCompo) Render() app.UI {
return app.Div().Body( // Div Container
app.H1().Text("Title"), // First child
app.P().Text("Content"), // Second child
)
}
Self Closing Elements
A self-closing element is an HTML element that cannot contain other UI elements.
func (c *myCompo) Render() app.UI {
return app.Img().Src("/myImage.png")
}
Attributes
HTML element interfaces provide methods to set element attributes. Here is an example that set a <div>
’s class:
func (c *myCompo) Render() app.UI {
return app.Div().Class("my-class")
}
Multiple attributes are set by using the chaining mechanism:
func (c *myCompo) Render() app.UI {
return app.Div().
ID("id-name").
Class("class-1").
Class("class-2")
}
Style
Style is an attribute that sets the element style with CSS.
func (c *myCompo) Render() app.UI {
return app.Div().Style("width", "400px")
}
Like the Class()
attribute, multiple styles are set by using the chaining mechanism:
func (c *myCompo) Render() app.UI {
return app.Div().
Style("width", "400px").
Style("height", "200px").
Style("background-color", "deepskyblue")
}
Event handlers
Event handlers are functions that are called when an HTML event occurs. They must have the following signature:
func(ctx app.Context, e app.Event)
Like attributes, HTML element interfaces provide methods to associate an event to a given handler:
func (c *myCompo) Render() app.UI {
return app.Div().OnClick(c.onClick)
}
func (c *myCompo) onClick(ctx app.Context, e app.Event) {
fmt.Println("onClick is called")
}
The Context argument embeds several go-app tools that help in creating responsive UIs. Usable with any function accepting a Go standard context, it is canceled when the source of the event is dismounted. The source element value can be retrieved with the JSSrc field:
func (c *myCompo) Render() app.UI {
return app.Div().OnChange(c.onChange)
}
func (c *myCompo) onChange(ctx app.Context, e app.Event) {
v := ctx.JSSrc().Get("value")
}
ctx.JSSrc
and Event are JavaScript objects wrapped in Go interfaces.
Text
Text() represents simple HTML text. Here is an example that display a Hello World
text:
func (c *myCompo) Render() app.UI {
return app.Div().Body( // Container
app.Text("Hello"), // First text
app.Text("World"), // Second text
)
}
When an HTML element embeds a single text element, HTML element’s Text()
method can be used instead:
func (c *myCompo) Render() app.UI {
return app.Div().Text("Hello World")
}
Raw elements
Raw elements are elements representing plain HTML code. Be aware that using them is unsafe since there is no check on HTML format.
Here is an example that creates a <svg>
element.
func (c *myCompo) Render() app.UI {
return app.Raw(`
<svg width="100" height="100">
<circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" />
</svg>
`)
}
Nested Components
Components are structs that let you split the UI into independent and reusable pieces. They can be used within other components to achieve more complex UIs.
Here is an example where a component named foo
embeds a text and another component named bar
.
// foo component:
type foo struct {
app.Compo
}
func (f *foo) Render() app.UI {
return app.P().Body(
app.Text("Foo, "), // Simple HTML text
&bar{}, // Nested bar component
)
}
// bar component:
type bar struct {
app.Compo
}
func (b *bar) Render() app.UI {
return app.Text("Bar!")
}
Condition
A Condition is a construct that selects the UI elements that satisfy a condition. They are created by calling the If() function.
If
Here is an If example that shows a title only when the showTitle
value is true
:
type myCompo struct {
app.Compo
showTitle bool
}
func (c *myCompo) Render() app.UI {
return app.Div().Body(
app.If(c.showTitle,
app.H1().Text("hello"),
),
)
}
ElseIf
Here is an ElseIf example that shows a title in different colors depending on an int
value:
type myCompo struct {
app.Compo
color int
}
func (c *myCompo) Render() app.UI {
return app.Div().Body(
app.If(c.color > 7,
app.H1().
Style("color", "green").
Text("Good!"),
).ElseIf(c.color < 4,
app.H1().
Style("color", "red").
Text("Bad!"),
).Else(
app.H1().
Style("color", "orange").
Text("So so!"),
),
)
}
Else
Here is an Else example that shows a simple text when the showTitle
value is false
:
type myCompo struct {
app.Compo
showTitle bool
}
func (c *myCompo) Render() app.UI {
return app.Div().Body(
app.If(c.showTitle,
app.H1().Text("hello"),
).Else(
app.Text("world"), // Shown when showTitle == false
),
)
}
Range
Range represents a range loop that shows UI elements generated from a slice or map. They are created by calling the Range() function.
Slice
Here is a slice example that shows an unordered list from a []string
:
func (c *myCompo) Render() app.UI {
data := []string{
"hello",
"go-app",
"is",
"sexy",
}
return app.Ul().Body(
app.Range(data).Slice(func(i int) app.UI {
return app.Li().Text(data[i])
}),
)
}
Map
Here is a map example that shows an unordered list from a map[string]int
:
func (c *myCompo) Render() app.UI {
data := map[string]int{
"Go": 10,
"JavaScript": 4,
"Python": 6,
"C": 8,
}
return app.Ul().Body(
app.Range(data).Map(func(k string) app.UI {
s := fmt.Sprintf("%s: %v/10", k, data[k])
return app.Li().Text(s)
}),
)
}
Form helpers
Form helpers are component methods that help to map HTML form element values to component fields.
ValueTo
ValueTo maps, when it exists, an HTML element value property to a given variable.
Here is a Hello component version that uses the ValueTo()
method to get the username from its input rather than defining an event handler:
type hello struct {
app.Compo
name string
}
func (h *hello) Render() app.UI {
return app.Div().Body(
app.H1().Text("Hello " + h.name),
app.P().Body(
app.Input().
Type("text").
Value(h.name).
Placeholder("What is your name?").
AutoFocus(true).
// Here the username is directly mapped from the input's change
// event.
OnChange(h.ValueTo(&h.name)),
),
)
}