Frontend: HB (HTML Builder)

Learn how to use the HB (HTML Builder) package for building HTML in Go.

Introduction to HB (HTML Builder)

HB is a pure Go HTML builder that allows you to create HTML elements programmatically. It provides a fluent, declarative interface for building complex HTML structures without the need for template files or mixing multiple languages.

What is HB?

HB (HTML Builder) is a Go package that enables developers to construct HTML and XHTML documents using idiomatic Go code. Instead of writing raw HTML strings or juggling template engines, you describe your UI structure directly in Go, using a chainable, readable API. This approach is both expressive and safe, and it integrates seamlessly with Go's type system.

Benefits of the Declarative Approach

1. Valid HTML/XHTML Output

  • HB guarantees that the HTML you generate is always valid and well-formed. This is because the API enforces correct nesting and attribute usage at compile time, reducing the risk of broken markup and runtime errors.

2. Reusability and Composition

  • UI components can be defined as Go functions or structs and reused throughout your application. You can compose complex layouts from smaller, reusable building blocks, making your codebase modular and maintainable.

3. Idiomatic Go —No Multiple Languages

  • All UI logic, structure, and behavior are written in Go. There is no need to context-switch between Go, HTML, and template languages. This leads to:
    • Easier onboarding for Go developers
    • Fewer bugs due to language mismatch
    • Unified tooling (formatters, linters, IDE support)

4. Type Safety and Compile-Time Checks

  • Go's static type system helps catch errors early. You benefit from autocompletion, refactoring tools, and type checking, which are not available when using raw HTML strings or template files.

5. Dynamic and Conditional Rendering

  • You can use Go's full power (loops, conditionals, functions) to dynamically generate HTML. This is especially useful for rendering lists, tables, or conditional UI elements without awkward template syntax.

6. No Template Injection Vulnerabilities

  • By avoiding template engines and raw string concatenation, you reduce the risk of injection attacks. HB escapes content appropriately, making your application more secure by default.

7. Maintainability and Refactoring

  • Since your UI is pure Go code, you can use Go's refactoring tools and static analysis to maintain and evolve your UI codebase. This is much harder with string-based templates.

8. Performance

  • HB generates HTML directly and efficiently. There is no template parsing or interpretation at runtime, resulting in faster page rendering and lower overhead.

Example: Building a Simple Page

import "github.com/gouniverse/hb"

func buildHTML() string {
    div := hb.Div().
        ID("content").
        Class("container").
        Child(hb.H1().Text("Hello, World!")).
        Child(hb.P().Text("Welcome to Dracory"))
    return div.ToHTML()
}

## Example: Conditional Rendering with ChildIf and AttrIf

You can use `ChildIf` to conditionally add a child element, and `AttrIf` to conditionally add an attribute. This is useful for showing error messages, toggling classes, or adding attributes only when certain conditions are met.

```go
func buildForm(errorMessage string, isDisabled bool) hb.TagInterface {
    return hb.Form().
        Method("POST").
        Action("/submit").
        ChildIf(errorMessage != "", hb.Div().
            Class("alert alert-danger").
            Text(errorMessage)).
        Child(hb.Input().
            Type("text").
            Name("username").
            AttrIf("disabled", "disabled", isDisabled)).
        Child(hb.Button().
            Type("submit").
            Class("btn btn-primary").
            Text("Submit"))
}
  • ChildIf(errorMessage != "", ...) will only add the error message div if errorMessage is not empty.
  • AttrIf("disabled", "disabled", isDisabled) will only add the disabled attribute if isDisabled is true.

This pattern keeps your UI logic clean, readable, and idiomatic Go.

Advanced Conditional Rendering: ChildIfElse and ChildIfF

  • ChildIfElse(condition, ifTag, elseTag) allows you to render one element if the condition is true, and another if it is false.
  • ChildIfF(condition, childFunc) lets you pass a condition and a function that returns the child. The child is only constructed and rendered if the condition function returns true. This is useful for expensive or dynamic content, such as rendering a list of blog posts only if they exist.
// Example: Show different message based on login status
form := hb.Form().
    ChildIfElse(
        userIsLoggedIn, // bool
        hb.Div().Text("Welcome back!"),
        hb.Div().Text("Please log in."),
    )

// Example: Only render blog posts section if posts exist
form := hb.Form().
    ChildIfF(
        haveBlogPosts, // func() bool
        func() hb.TagInterface {
            // retrieve blog posts, images, authors, etc.
            return hb.Div().
                Class("blog-list").
                Children(blogPostsToTags(blogPosts))
        },
    )

// Example: Render message if no blog posts exist
form := hb.Form().
    ChildIf(
        !hasBlogPosts, // bool
        hb.Div().Class("no-posts").Text("No blog posts available."),
    )
  • ChildIfF(haveBlogPosts, func() hb.TagInterface { ... }) will only add the blog list if haveBlogPosts() returns true.
  • ChildIf(!hasBlogPosts, ...) will only add the message if hasBlogPosts is false.

This pattern ensures that expensive or dynamic UI elements are only created and rendered if needed, keeping your code efficient and clean.

Why Choose Declarative UI in Go?

By using HB and the declarative approach, you:

  • Ensure your HTML is always valid and standards-compliant
  • Write less boilerplate and avoid repetitive code
  • Gain all the benefits of Go: tooling, type safety, and performance
  • Create UIs that are easier to reason about, test, and maintain
  • Avoid the pitfalls of mixing multiple languages or relying on fragile string templates
  • Easily cache rendered HTML output, since everything is generated in pure Go and can be stored or reused efficiently
  • Express UI logic directly in Go: HB supports conditional rendering and attributes with methods like ChildIf and AttrIf, allowing you to show or hide elements and set attributes based on runtime conditions (e.g., ChildIf(errorMessage != ""))

In summary: A declarative, Go-native approach to building HTML results in more robust, maintainable, and secure web applications. HB empowers you to build modern UIs quickly, with confidence, and without leaving the Go ecosystem.

Menu