Control flow
Use Go control flow inside { … } to decide which markup renders. Conditions, variables, and scopes follow normal Go rules.
If / else
An if block renders its markup when the condition is true. Add else for the alternative; without it, a false condition renders nothing.
package views
component Inbox(name string, count int) {
<section>
<h1>Hi { name }</h1>
{ if count > 0 {
<p class="badge">{ count } new</p>
} else {
<p>all caught up</p>
} }
</section>
}Renders:
<section><h1>Hi World</h1><p class="badge">2 new</p></section>Range
A for … range block renders its markup once for each value. The loop variables are in scope inside the block.
package views
type Item struct {
Name string
Count int
}
component List(items []Item) {
<ul>
{ for _, it := range items {
<li>{ it.Name }: { it.Count }</li>
} }
</ul>
}Renders:
<ul><li>alpha: 1</li><li>beta: 2</li></ul>Any value supported by Go's range can be used here.
Switch
A switch block renders the matching case, or default when no case matches.
package views
component Badge(kind string) {
<span>
{ switch kind {
case "warn":
<b>warning</b>
case "err":
<b>error</b>
default:
<b>info</b>
} }
</span>
}Renders:
<span><b>warning</b></span>Cases use normal Go syntax, including comma-separated values.
Text at the start of its own line inside a case body is read as the next arm's label if it looks like one (case <expr>: or default:, colon on the same line) — mid-line text is unaffected, and a line-leading case 1: compiles silently as a new arm, so wrap such text in an interpolation (e.g. {"default: 5"}) or an element to render it literally. A label whose case list spans lines is only recognized when it follows markup, not text — keep arm labels on one line.
Init statements
An if can declare values before its condition. Those values remain in scope through every branch, which is useful for checking a result and its error together.
package views
func loadUser(id string) (string, error) { return "User:" + id, nil }
component Profile(id string) {
<div>
{ if name, err := loadUser(id); err != nil {
<span class="err">{ err.Error() }</span>
} else {
<span>{ name }</span>
} }
</div>
}Renders:
<div><span>User:42</span></div>The same form works for map lookups, type assertions, and other expressions that return multiple values.
Whitespace in control-flow bodies
Whitespace inside { if }, { for }, and { switch } bodies follows the same whitespace rule as element bodies: whitespace between content is preserved (a run with a newline collapses away; an inline run collapses to one space). Whitespace immediately inside the control-flow braces is ignored, like the interior of { expr }. To keep a separator space next to a conditional, put it in the surrounding markup rather than at the block's inner edge:
<title>{ if !isProd { {env} - } } {page} - One Learning</title>