-
-
Notifications
You must be signed in to change notification settings - Fork 397
Declarative Syntax
Writing components requires to describe how the UI looks like.
In the previous version of this package, this was done by writing HTML code as templated strings where Go code was called by hidden mechanisms.
While it was working well, it had some drawback related to HTML written in Go strings:
- No linter
- No code format
- No code editor auto-complete
The result was that it was easy to make mistakes when writing HTML.
The app package now provides interfaces and functions based on HTML elements. By using a chaining mechanism and the Go syntax, writing a UI is now done in a declarative fashion, without using another language.
Here is an example that describes a title and its text:
ui := app.Div().Body(
app.H1().
Class("title").
Body(
app.Text("Build a GUI with Go"),
),
app.P().
Class("text").
Body(
app.Text("Just because Go and this package are really awesome!"),
),
)The app package provides an interface for each standard HTML element.
Here is a simplified version of the interface for a <div>:
type HTMLDiv interface {
// Attributes:
Body(nodes ...Node) HTMLDiv
Class(v string) HTMLDiv
ID(v string) HTMLDiv
Style(k, v string) HTMLDiv
// Event handlers:
OnClick(h EventHandler) HTMLDiv
OnKeyPress(h EventHandler) HTMLDiv
OnMouseOver(h EventHandler) HTMLDiv
}An HTML element can be created by calling a function named after its name:
div := app.Div()Element interfaces provide methods to set its attributes:
div := app.Div().Class("my-class")Multiple attributes can be set by using the chaining mechanism:
div := app.Div().
ID("id-name").
Class("class-name")Style is an attribute that sets the element style with CSS. It is set by calling the Style() method with a CSS property name and value.
div := app.Div().Style("width", "400px")Multiple styles can be set by calling the Style() method successively:
div := app.Div().
Style("width", "400px").
Style("height", "200px").
Style("background-color", "deepskyblue")Event handlers are functions that are called when an HTML event occurs. They must have the following signature:
func(src app.Value, e app.Event)Like attributes, element interfaces provide methods to attach event handlers the events it generates:
onClick := func(src app.Value, e app.Event) {
fmt.Println("onClick is called")
}
div := app.Div().OnClick(onClick)Note that app.Value and app.Event are JavaScript objects wrapped in Go interfaces. See the JS Values topic to know more about it.
Standard elements are elements that can contain other elements. To do so they provide the Body() method which takes other elements as parameters:
div := app.Div().Body(
app.H1().Body(
app.Text("Title"),
),
app.P().Body(
app.Text("Content"),
),
)Self-closing elements are elements that cannot contain other elements.
img := app.Img().Src("/myImage.png")
br := app.Br()Text represents simple HTML text. It is created by calling the app.Text() function:
text := app.Text("hello world")There is some case where some raw HTML code might be required. It can be done by using the app.Raw() function with HTML code as argument:
svg := app.Raw(`
<svg width="100" height="100">
<circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" />
</svg>
`)Be aware that using this function is unsafe since there is no check on HTML construct or format.
Components are structs that let you split the UI into independent and reusable pieces. They implement the app.Composer interface and can be embedded within a standard HTML element:
// bar component
type bar struct {
app.Compo
}
func (b *bar) Render() app.UI {
return app.Text("bar")
}
// A function that returns a div that contains a text and a bar component.
func fooBar() app.UI {
return app.Div().Body(
app.Text("foo"),
&bar{},
)
}Condition is a construct that selects the UI elements that satisfy a condition.
Here is an If example that shows a title only when the showTitle value is true.
var showTitle bool
div := app.Div().Body(
app.If(showTitle,
app.H1().Body( // Shown when showTitle == true
app.Text("hello"),
),
),
)Here is an ElseIf example that shows a title in different colors depending on an int value.
var value int
div := app.Div().Body(
app.If(value > 7,
app.H1().
Style("color", "green").
Body(
app.Text("Good!"),
),
).ElseIf(value < 4,
app.H1().
Style("color", "red").
Body(
app.Text("Bad!"),
),
).Else(
app.H1().
Style("color", "orange").
Body(
app.Text("So so!"),
),
),
)Here is an Else example that shows a simple text when the showTitle value is false.
var showTitle bool
div := app.Div().Body(
app.If(showTitle,
app.H1().Body(
app.Text("hello"),
),
).Else(
app.Text("world"), // Shown when showTitle == false
),
)