On this page
1 — Install 2 — Write a component 3 — Create an engine 4 — Render with props 5 — Use slots Component system Go API reference How-to guidesTutorial
Build your first htmlc component from scratch. This walkthrough takes you from installation to rendering a component with props and slots in about five minutes.
Step 1 — Install htmlc
Add the package to your Go module:
go get github.com/dhamidi/htmlc
The CLI is optional but handy for testing components without writing Go code:
go install github.com/dhamidi/htmlc/cmd/htmlc@latest
Step 2 — Write a component
Create a directory called components/ and add a file named Card.vue:
<!-- components/Card.vue -->
<template>
<div class="card">
<h2>{{ title }}</h2>
<slot>No content provided.</slot>
</div>
</template>
<style scoped>
.card {
border: 1px solid #ccc;
border-radius: 8px;
padding: 1rem;
}
</style>
The {{ title }} interpolation reads the title prop. The <slot> element is a placeholder for content supplied by a parent component; its children are the fallback rendered when no content is provided.
Step 3 — Create an engine
Call htmlc.New with the directory that contains your .vue files. The engine discovers and registers every component automatically.
package main
import (
"log"
"github.com/dhamidi/htmlc"
)
func main() {
engine, err := htmlc.New(htmlc.Options{
ComponentDir: "./components",
})
if err != nil {
log.Fatal(err)
}
_ = engine
}
Step 4 — Render with props
Call RenderFragmentString to render a component to a string. Pass props as a map[string]any.
html, err := engine.RenderFragmentString("Card", map[string]any{
"title": "Hello, htmlc!",
})
if err != nil {
log.Fatal(err)
}
fmt.Println(html)
Expected output (style block prepended by the engine):
<style>
.card[data-v-…]{border:1px solid #ccc;border-radius:8px;padding:1rem}
</style>
<div class="card" data-v-…>
<h2>Hello, htmlc!</h2>
No content provided.
</div>
The fallback text "No content provided." is rendered because no slot content was passed. Step 5 shows how to supply it.
Step 5 — Use slots
Slot content is supplied through component composition in a .vue template. There is no $slots key in the Go props map; htmlc does not support injecting raw HTML into slots via the data map.
Create a wrapper component that uses Card with slot content:
<!-- components/WelcomeCard.vue -->
<template>
<Card title="Welcome">
<p>This paragraph is rendered inside the Card's slot.</p>
</Card>
</template>
Then render the wrapper from Go:
html, err := engine.RenderFragmentString("WelcomeCard", nil)
if err != nil {
log.Fatal(err)
}
fmt.Println(html)
Expected output:
<div class="card" data-v-…>
<h2>Welcome</h2>
<p>This paragraph is rendered inside the Card's slot.</p>
</div>
The same pattern applies to named and scoped slots — the parent component uses <template #name> syntax in the .vue file to target specific slots. See the component system reference for named and scoped slot examples.
Dynamic slot content from Go
If you need to inject a dynamic HTML string into a component from Go, use a regular prop with v-html instead of a slot:
<!-- components/Card.vue -->
<div class="card">
<h2>{{ title }}</h2>
<div v-html="body"></div>
</div>
html, err := engine.RenderFragmentString("Card", map[string]any{
"title": "Hello",
"body": "<p>Dynamic content from Go</p>",
})