Skip to content

Examples

A gallery of gsx features. Each example is compiled and checked in CI; click Open in Playground to run and edit it live.

Basics

Interpolation & props

Components take a typed props struct; {expr} interpolates Go values, HTML-escaped.

gsx
package views

component Greeting(name string, count int) {
	<p>Hello, { name }! You have { count } messages.</p>
}

▶ Open in Playground

Attributes

Expression attributes (attr={expr}), boolean attributes, and a conditional attribute via { if … { attr=… } }.

gsx
package views

component Link(url string, label string, external bool, featured bool) {
	<a
		href={url}
		data-count={3}
		aria-current={external}
		{ if featured {
			class="featured"
		} }
	>
		{ label }
	</a>
}

▶ Open in Playground

Auto-escaping & safe raw

User input is HTML-escaped by construction — no XSS. Use gsx.Raw / gsx.RawURL to opt out deliberately.

gsx
package views

// User input is HTML-escaped by construction — no XSS.
component Comment(body string) {
	<blockquote>{ body }</blockquote>
}

▶ Open in Playground

Control flow

If / else

Brace { if … else … } blocks contribute markup conditionally.

gsx
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>
}

▶ Open in Playground

Loops over lists

{ for … := range … } renders markup per element using a real Go range loop.

gsx
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>
}

▶ Open in Playground

Switch

{ switch … } selects one branch of markup; default handles the rest.

gsx
package views

component Badge(kind string) {
	<span>
		{ switch kind {
			case "warn":
				<b>warning</b>
			case "err":
				<b>error</b>
			default:
				<b>info</b>
		} }
	</span>
}

▶ Open in Playground

Components & composition

Components & props

Call a component with a typed props struct; boolean props pass bare (featured).

gsx
package views

component Card(title string, featured bool, count int) {
	<div class={ "card", "card-featured": featured }>
		<h2>{ title }</h2>
		<span>{ count }</span>
	</div>
}

component Page(t string, n int) {
	<Card title={t} featured count={n}/>
}

▶ Open in Playground

Children

A component renders its nested markup via {children} (like JSX children / a Vue default slot).

gsx
package views

component Card(title string) {
	<article class="card">
		<h3>{ title }</h3>
		<div class="card__body">{ children }</div>
	</article>
}

component Page() {
	<Card title="Hello">
		<em>composed</em>
	</Card>
}

▶ Open in Playground

Named slots

Pass markup into named gsx.Node props — header and footer slots.

gsx
package views

import "github.com/gsxhq/gsx"

component Panel(header gsx.Node, footer gsx.Node) {
	<div class="panel">
		<header>{ header }</header>
		<footer>{ footer }</footer>
	</div>
}

component Page() {
	<Panel header={ <h1>H</h1> } footer="F"/>
}

▶ Open in Playground

Template composition

A shared component library composed by a page method — multiple files, one render entry. This is the multi-file showcase.

components.gsx

gsx
package views

component Button(label string) {
	<button class="btn">{ label }</button>
}

component Card(title string) {
	<section class="card">
		<h2>{ title }</h2>
		{ children }
	</section>
}

page.gsx

gsx
package views

type HomePage struct {
	Title string
}

component (p HomePage) Render() {
	<main>
		<Card title={p.Title}>
			<Button label="Save"/>
		</Card>
	</main>
}

▶ Open in Playground

Fallthrough attributes

Undeclared call-site attributes (class, data-, hx-) fall through to the component's root element; class merges (caller-wins).

gsx
package views

component Button(variant string) {
	<button class="btn" data-variant={variant}>{ children }</button>
}

component Page() {
	<Button variant="primary" class="w-full" data-test="x" hx-post="/go">
		Save
	</Button>
}

▶ Open in Playground

Method components

Components can be methods on a type, so page state lives on the receiver (p) and per-call data in the props struct.

gsx
package views

type UsersPage struct {
	Title string
	Sort  string
}

component (p UsersPage) Grid(sort string) {
	<div>{ sort }-{ p.Title }</div>
}

▶ Open in Playground

Styling

Composable class

The class attribute takes "always" entries and "name": cond toggles (like clsx / Vue :class).

gsx
package views

component Tag(label string, active bool) {
	<span class={ "tag", "tag--active": active }>{ label }</span>
}

▶ Open in Playground

Style blocks

A <style> block interpolates values with @{ … }; interpolated values are CSS-sanitized by construction.

gsx
package views

component Card(w int, userColor string) {
	<style>
		.card {
			width: @{ w }px;
			color: @{ userColor };
		}
	</style>
}

▶ Open in Playground

Transforming values

Pipelines / filters

Transform values with typed filter pipelines — { x |> trim |> upper } — drawn from the gsx info registry.

gsx
package views

component Hi(name string) {
	<p>{ name |> trim |> upper }</p>
}

▶ Open in Playground

Interactive & whole-page

Fragments

A component can return multiple roots with no wrapper element using <>…</>.

gsx
package views

component Pair(a string, b string) {
	<><span>{ a }</span><span>{ b }</span></>
}

▶ Open in Playground

Forms

A reusable Field component forwards undeclared attributes ({ attrs... }) onto its input, so callers add type/name/required without Field declaring them.

gsx
package views

component Field(label string) {
	<div class="field">
		<label>{ label }</label>
		<input class="control" { attrs... }/>
	</div>
}

component LoginForm() {
	<form method="post" action="/login">
		<Field label="Email" type="email" name="email" required/>
		<Field label="Password" type="password" name="password" required/>
		<button type="submit">Sign in</button>
	</form>
}

▶ Open in Playground

JS attributes & data islands

@click={ gsx.RawJS(…) } emits a vouched event handler; a <script type="application/json"> island serializes typed Go data with @{ … } for client JS.

gsx
package views

import "github.com/gsxhq/gsx"

type Config struct {
	Env  string
	Beta bool
}

component Widget(cfg Config) {
	<div>
		<button @click={gsx.RawJS("toggle()")}>Toggle</button>
		<script type="application/json" id="cfg">@{ cfg }</script>
	</div>
}

▶ Open in Playground

Full HTML document

Render a whole page, including <!DOCTYPE html>, as one component.

gsx
package views

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

▶ Open in Playground