Gostar HTML Builder for Go
repository·main·Indexed 41 days ago
https://github.com/delaneyj/gostarA fluent, type-safe HTML builder for Go that provides a programmatic way to construct HTML using a DSL based on the HTML Living Standard. It replaces string concatenation and standard templates with a fluent API and ElementRenderer types for creating reusable components.
What's inside Gostar
- Gostar is a fluent HTML builder for Go. It is designed to replace string concatenation or standard Go templates with a fluent API that allows for programmatic and natural HTML construction. The library is built directly from the HTML Living Standard, automatically providing conversions for all HTML elements and attributes.
Create reusable HTML components with ElementRenderer
mainGostar uses a fluent API where functions return
ElementRenderertypes. Because these are just functions, you can compose them into complex structures or define your own reusable components by creating functions that return anElementRenderer.Common patterns include:
- Composition: Nesting element functions (e.g.,
DIV(P().Text("..."))). - Custom Components: Defining variables or functions that encapsulate specific HTML structures.
- Iteration: Using helper functions like
Rangeto iterate over slices and generate elements for each item.
// Example of a custom component var header = func(title string) ElementRenderer { return HEADER( TITLE().TextF("%s's Home Page", title), DIV().CLASS("header").Text("Page Header"), ) }- Composition: Nesting element functions (e.g.,
Install and import Gostar
mainTo use Gostar, import the
elementspackage. The author recommends using a dot import to avoid repetitive package prefixes, as all HTML tags and attributes are provided as uppercase functions to distinguish the DSL from Go keywords.import . "github.com/delaneyj/gostar/elements"import . "github.com/delaneyj/gostar/elements"Example: Building a complete HTML page
mainThe following example demonstrates how to use Gostar to build a full HTML document, including a doctype, body, navigation, and content sections using custom components and iteration.
import ( "net/http" . "github.com/delaneyj/gostar/elements" ) type Navigation struct { Link string Item string } type User struct { FirstName string RawContent string EscapedContent string } var ( header = func(title string) ElementRenderer { return HEADER( TITLE().TextF("%s's Home Page", title), DIV().CLASS("header").Text("Page Header"), ) } navigation = func(nav []*Navigation) ElementRenderer { return NAV( UL( Range(nav, func(n *Navigation) ElementRenderer { return LI( A().HREF(n.Link).Text(n.Item), ) }), ).CLASS("navigation"), ) } footer = func() ElementRenderer { return FOOTER(DIV().CLASS("footer").Text("copyright 2016")) } index = func(u *User, nav []*Navigation, title string) ElementRenderer { return Group( Text("<!DOCTYPE html>"), HTML( BODY( header(title), navigation(nav), SECTION( DIV( DIV( H4().TextF("Hello %s", u.FirstName), DIV().CLASS("raw").Text(u.RawContent), DIV().CLASS("enc").Escaped(u.EscapedContent), ).CLASS("welcome"), Range(lo.Range(5), func(i int) ElementRenderer { count := i + 1 return Tern( n count == 1, P().TextF("%s has %d message", u.FirstName, count), P().TextF("%s has %d messages", u.FirstName, count), ), }), ).CLASS("content"), ), ), footer(), ), ), ), ) } ) func indexHandler(w http.ResponseWriter, r *http.Request) { user := &User{ FirstName: "John", RawContent: `<a href="http://john.com">This is some raw content</a>`, EscapedContent: `<a href="http://john.com">This is some encoded content</a>`, } nav := []*Navigation{ {Link: "/home", Item: "Home"}, {Link: "/about", Item: "About"}, } index(user, nav, "John").Render(w) }