Guide / 04 — Templates
Components
Components are .stew files with names starting with an uppercase letter. They can be organized in any project subfolder (except the root). They receive structured Props and can expose a slot to inject content.
Creating a component
The component/Card.stew file:
<goscript>
// Declare component props
type CardProps struct {
Title string
Description string
}
</goscript>
<div class="p-6 bg-white rounded-2xl border border-stone-200 shadow-sm">
<h2 class="text-xl font-bold mb-2">{{ props.Title }}</h2>
<p class="text-stone-500 text-sm">{{ props.Description }}</p>
<!-- Optional slot to inject content -->
<slot />
</div>
Rule: Even if a component has no props, the
type XxxProps struct {} structure must be declared (empty). The compiler needs it to generate the Go signature.
Usage
To use a component in a page or another component, you must first import it within a <goscript> block. Then, use its name as an HTML tag.
<!-- pages/@page.stew -->
<goscript>
import "../components/Card.stew"
</goscript>
<!-- Auto-closing (no slot) -->
<Card Title="My title" Description="My description" />
<!-- With slot: content between opening and closing tags -->
<Card Title="Actions" Description="Action buttons">
<div class="mt-4 flex gap-2">
<button class="px-4 py-2 bg-stone-900 text-white rounded-lg">Validate</button>
<button class="px-4 py-2 border rounded-lg">Cancel</button>
</div>
</Card>
Typed Components (Props)
To pass data to a component, define a structure named {Name}Props. The compiler will inject a props variable of this type into the component's scope.
<!-- components/User.stew -->
<goscript>
type UserProps struct {
Name string
Age int
}
</goscript>
<div>
<p>Name: {{ props.Name }}</p>
<p>Age: {{ props.Age }}</p>
</div>
Note on typing: The Stew compiler automatically converts HTML attributes (strings) to simple Go types (int, bool, float) defined in your Props struct during the call.
Dynamic props
Props can receive Go expressions via the {{ }} syntax:
{{ each data.Products as p, i }}
<Card Title="{{ p.Name }}" Description="{{ p.Sku }}" />
{{ end }}
Nested components
A component can import and use other components just like a page does:
<!-- component/Card.stew -->
<goscript>
import "./Badge.stew"
type CardProps struct {
Title string
Badge string
}
</goscript>
<div class="...">
<Badge Label="{{ props.Badge }}" />
<h2>{{ props.Title }}</h2>
<slot />
</div>
What the compiler generates
For Card.stew, the compiler generates Card.go:
// Code generated by Stew-Lang. DO NOT EDIT.
package component
import (
"io"
github.com/ZiplEix/stew/sdk/stew"
)
type CardProps struct {
Title string
Description string
}
func Card(w io.Writer, data stew.PageData, props CardProps, slot func()) {
// HTML rendering before the slot
w.Write([]byte(`<div class="p-6 ...">`))
w.Write([]byte(html.EscapeString(fmt.Sprint(props.Title))))
// ...
if slot != nil { slot() } // Slot injection
w.Write([]byte(`</div>`))
}