| name | gomponents |
| description | Building, rendering, or editing any HTML or UI in a Go application means using gomponents — ALWAYS invoke this skill as your FIRST action, before any Read, Write, Edit, or Bash. This fires for any view, page, layout, component, form, table, navbar, footer, or list that renders to HTML; any function returning a `Node`; anything in the `html` package; and converting HTML or templates into Go. It is a hard requirement — the user writes all HTML through gomponents, a pure-Go component library whose conventions (dot imports, `Node` composition, `Map`/`If`/`Iff`, `Group`, HTML5 documents) ordinary Go and HTML habits get wrong. Load it even when the Go skill also applies. Skip only when no HTML or view code is touched (pure database, handler, or business logic; plain `.css`/`.js`/`.html` files; conceptual questions with no code). |
| license | MIT |
gomponents
Overview
gomponents is a pure Go HTML component library that treats HTML elements as composable Go values. Everything is built on the Node interface, making HTML construction type-safe and composable.
When to Use This Skill
Use this skill when:
- Reading or writing gomponents code
- Building server-side HTML views in Go applications
- Creating reusable HTML components in Go
Core Interface
Everything in gomponents implements the Node interface:
type Node interface {
Render(w io.Writer) error
}
Essential Functions
Element and Attribute Creation
El(name string, children ...Node) - Create custom HTML elements
Attr(name string, value ...string) - Create custom attributes
Most standard HTML5 elements and attributes are available as functions in the html package:
- Elements:
Div(), Span(), P(), A(), etc.
- Attributes:
Class(), ID(), Href(), Src(), etc.
Note: nil Nodes are ignored during rendering, so it's safe to pass nil nodes to elements.
Text Content
Text(string) - HTML-escaped text content
Textf(format string, args...) - Formatted, escaped text
Raw(string) - Unescaped HTML
Rawf(format string, args...) - Formatted, unescaped content
Composition
Group([]Node) - Combine multiple nodes
Map[T]([]T, func(T) Node) - Transform slices into node sequences
If(condition bool, node Node) - Conditional rendering
Iff(condition bool, func() Node) - Lazy conditional rendering (deferred evaluation)
Import Convention
Contrary to common Go idioms, dot imports are recommended for gomponents to achieve DSL-like syntax:
import (
. "maragu.dev/gomponents"
. "maragu.dev/gomponents/html"
. "maragu.dev/gomponents/components"
)
This allows writing clean, HTML-like code:
Div(Class("container"),
H1(Text("Hello World")),
P(Text("Welcome to gomponents")),
)
Package Organization
maragu.dev/gomponents - Core interface and helper functions
maragu.dev/gomponents/html - All HTML5 elements and attributes
maragu.dev/gomponents/http - HTTP helpers for rendering components as responses
maragu.dev/gomponents/components - Higher-level utilities (HTML5 document structure, dynamic classes)
Common Patterns
Basic Component
func UserCard(name, email string) Node {
return Div(Class("user-card"),
H2(Text(name)),
P(Text(email)),
)
}
Conditional Rendering
func Alert(message string, isError bool) Node {
return Div(
If(isError, Class("error")),
If(!isError, Class("info")),
P(Text(message)),
)
}
Use If when the node is always safe to evaluate. Use Iff when the node might be nil and shouldn't be evaluated unless the condition is true.
func UserProfile(user *User) Node {
return Div(
H1(Text(user.Name)),
Iff(user.Avatar != nil, func() Node {
return Img(Src(user.Avatar.URL))
}),
)
}
Grouping Without a Parent Element
Use Group to group multiple nodes without wrapping them in a parent element:
func FormFields(required bool) Node {
return Group{
Label(For("email"), Text("Email")),
Input(Type("email"), ID("email")),
If(required, Span(Class("required"), Text("*"))),
}
}
List Rendering
func TodoList(todos []Todo) Node {
return Ul(Class("todo-list"),
Map(todos, func(t Todo) Node {
return Li(Text(t.Title))
}),
)
}
HTML Document
func Page(title string, body Node) Node {
return HTML5(HTML5Props{
Title: title,
Language: "en",
Head: []Node{
Link(Rel("stylesheet"), Href("/styles.css")),
},
Body: []Node{body},
})
}
HTTP Handler
import ghttp "maragu.dev/gomponents/http"
func HomeHandler(w http.ResponseWriter, r *http.Request) (Node, error) {
return Page("My App",
Div(Class("container"),
H1(Text("Hello, World!")),
),
), nil
}
http.HandleFunc("/", ghttp.Adapt(HomeHandler))
The http package provides:
Handler type - function signature that returns (Node, error)
Adapt(Handler) - converts Handler to http.HandlerFunc
- Error handling with custom status codes via
StatusCode() int interface