Skip to content

Elements ​

Elements use familiar HTML syntax: attributes go in the opening tag and children nest between opening and closing tags. Dynamic values use Go expressions in braces.

Tags and nesting ​

gsx
package views

component Card(title string, body string) {
	<article class="card">
		<h2>{title}</h2>
		<p>{body}</p>
	</article>
}

Static attributes use quoted strings, while dynamic attributes use expressions such as disabled={disabled}. See Attributes for boolean attributes, spreads, and composition.

Whether a tag is an element or a component depends on its name and declarations in the package. See Basic Syntax — Element or component?.

Void elements ​

HTML void elements have no children. Write them with />; they render without a separate closing tag.

gsx
package views

component AvatarField(src string, alt string, disabled bool) {
	<div>
		<img src={src} alt={alt}/>
		<br/>
		<input type="text" required disabled={disabled}/>
	</div>
}

Renders:

html
<div><img src="/avatar.png" alt="User"><br><input type="text" required disabled></div>

▶ Open in Playground

Tag serialization ​

gsx generates canonical HTML tag shapes regardless of how you write them:

  • <div/> (any non-void element, including SVG) renders as <div></div> — browsers ignore the / on non-void elements and would treat <div/> as an unclosed open tag.
  • <br/> and <br></br> both render as <br>.
  • A void element with children (<br>text</br>) is a compile error.

Set serialization = "verbatim" in gsx.toml to emit authored shapes unchanged.

gsx
package views

component Divider() {
	<section>
		<div role="separator"/>
		<p>Content after the divider stays outside it.</p>
	</section>
}

Renders:

html
<section><div role="separator"></div><p>Content after the divider stays outside it.</p></section>

▶ Open in Playground

Raw-text elements ​

The bodies of <script> and <style> are literal text, so < is not treated as a nested tag. Use @{ expression } for dynamic values inside them.

gsx
package views

component Tracker() {
	<script>
		const threshold = 5;
		if (count < threshold) { track("below"); }
	</script>
}

Renders:

html
<script>const threshold = 5;
if (count < threshold) { track("below"); }</script>

▶ Open in Playground

See JavaScript and Styling for interpolation and minification options.

Full documents ​

A component can render a complete HTML document. Place <!DOCTYPE html> before the root <html> element.

gsx
package views

component Page(title string) {
	<!DOCTYPE html>
	<html lang="en">
		<head>
			<title>{ title }</title>
		</head>
		<body>hi</body>
	</html>
}

Renders:

html
<!DOCTYPE html><html lang="en"><head><title>Home</title></head><body>hi</body></html>

▶ Open in Playground

Elements as values ​

An element can be used wherever Go expects an expression in a .gsx file: a variable initializer, return value, function argument, struct field, slice item, map item, or interpolation operand. The result is a gsx.Node.

gsx
package views

var help = <a href="/help">Help</a>
var empty = <><h2>No results</h2><p>Try another search.</p></>

component Page() {
	<main>{help}{empty}</main>
}

A fragment (<>…</>) works in the same expression positions when the value needs multiple sibling roots. See Fragments.