gomponents

package module
v0.20.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 9, 2024 License: MIT Imports: 4 Imported by: 244

README

Tired of complex template languages?

Logo

GoDoc Go codecov Go Report Card

Try view components in pure Go.

gomponents are view components written in pure Go. They render to HTML 5, and make it easy for you to build reusable components. So you can focus on building your app instead of learning yet another templating language.

The API may change until version 1 is reached.

Check out www.gomponents.com for an introduction.

Made in 🇩🇰 by maragu, maker of online Go courses.

Features

  • Build reusable view components
  • Write declarative HTML5 in Go without all the strings, so you get
    • Type safety
    • Auto-completion
    • Nice formatting with gofmt
  • Simple API that's easy to learn and use (you know most already if you know HTML)
  • Useful helpers like Text and Textf that insert HTML-escaped text, Map for mapping data to components, and If for conditional rendering.
  • No external dependencies

Usage

Get the library using go get:

go get github.com/maragudk/gomponents

The preferred way to use gomponents is with so-called dot-imports (note the dot before the gomponents/html import), to give you that smooth, native HTML feel:

package main

import (
	"net/http"

	g "github.com/maragudk/gomponents"
	c "github.com/maragudk/gomponents/components"
	. "github.com/maragudk/gomponents/html"
)

func main() {
	_ = http.ListenAndServe("localhost:8080", http.HandlerFunc(handler))
}

func handler(w http.ResponseWriter, r *http.Request) {
	_ = Page("Hi!", r.URL.Path).Render(w)
}

func Page(title, currentPath string) g.Node {
	return Doctype(
		HTML(
			Lang("en"),
			Head(
				TitleEl(g.Text(title)),
				StyleEl(Type("text/css"), g.Raw(".is-active{ font-weight: bold }")),
			),
			Body(
				Navbar(currentPath),
				H1(g.Text(title)),
				P(g.Textf("Welcome to the page at %v.", currentPath)),
			),
		),
	)
}

func Navbar(currentPath string) g.Node {
	return Nav(
		NavbarLink("/", "Home", currentPath),
		NavbarLink("/about", "About", currentPath),
	)
}

func NavbarLink(href, name, currentPath string) g.Node {
	return A(Href(href), c.Classes{"is-active": currentPath == href}, g.Text(name))
}

Some people don't like dot-imports, and luckily it's completely optional. If you don't like dot-imports, just use regular imports.

You could also use the provided HTML5 document template to simplify your code a bit:

package main

import (
	"net/http"

	g "github.com/maragudk/gomponents"
	c "github.com/maragudk/gomponents/components"
	. "github.com/maragudk/gomponents/html"
)

func main() {
	_ = http.ListenAndServe("localhost:8080", http.HandlerFunc(handler))
}

func handler(w http.ResponseWriter, r *http.Request) {
	_ = Page("Hi!", r.URL.Path).Render(w)
}

func Page(title, currentPath string) g.Node {
	return c.HTML5(c.HTML5Props{
		Title:    title,
		Language: "en",
		Head: []g.Node{
			StyleEl(Type("text/css"), g.Raw(".is-active{ font-weight: bold }")),
		},
		Body: []g.Node{
			Navbar(currentPath),
			H1(g.Text(title)),
			P(g.Textf("Welcome to the page at %v.", currentPath)),
		},
	})
}

func Navbar(currentPath string) g.Node {
	return Nav(
		NavbarLink("/", "Home", currentPath),
		NavbarLink("/about", "About", currentPath),
	)
}

func NavbarLink(href, name, currentPath string) g.Node {
	return A(Href(href), c.Classes{"is-active": currentPath == href}, g.Text(name))
}

For more complete examples, see the examples directory.

What's up with the specially named elements and attributes?

Unfortunately, there are four main name clashes in HTML elements and attributes, so they need an El or Attr suffix, respectively, to be able to co-exist in the same package in Go:

  • data (DataEl/DataAttr)
  • form (FormEl/FormAttr)
  • style (StyleEl/StyleAttr)
  • title (TitleEl/TitleAttr)

Documentation

Overview

Package gomponents provides view components in Go, that render to HTML 5.

The primary interface is a Node. It describes a function Render, which should render the Node to the given writer as a string.

All DOM elements and attributes can be created by using the El and Attr functions. The functions Text, Textf, Raw, and Rawf can be used to create text nodes, either HTML-escaped or unescaped. See also helper functions Group, Map, and If for mapping data to Nodes and inserting them conditionally.

For basic HTML elements and attributes, see the package html. For higher-level HTML components, see the package components. For SVG elements and attributes, see the package svg. For HTTP helpers, see the package http.

Index

Examples

Constants

View Source
const (
	ElementType = NodeType(iota)
	AttributeType
)

Variables

This section is empty.

Functions

This section is empty.

Types

type Node

type Node interface {
	Render(w io.Writer) error
}

Node is a DOM node that can Render itself to a io.Writer.

func Attr

func Attr(name string, value ...string) Node

Attr creates an attribute DOM Node with a name and optional value. If only a name is passed, it's a name-only (boolean) attribute (like "required"). If a name and value are passed, it's a name-value attribute (like `class="header"`). More than one value make Attr panic. Use this if no convenience creator exists.

Example (Bool)
package main

import (
	"os"

	g "github.com/maragudk/gomponents"
)

func main() {
	e := g.El("input", g.Attr("required"))
	_ = e.Render(os.Stdout)
}
Output:

<input required>
Example (Name_value)
package main

import (
	"os"

	g "github.com/maragudk/gomponents"
)

func main() {
	e := g.El("div", g.Attr("id", "hat"))
	_ = e.Render(os.Stdout)
}
Output:

<div id="hat"></div>

func El

func El(name string, children ...Node) Node

El creates an element DOM Node with a name and child Nodes. See https://dev.w3.org/html5/spec-LC/syntax.html#elements-0 for how elements are rendered. No tags are ever omitted from normal tags, even though it's allowed for elements given at https://dev.w3.org/html5/spec-LC/syntax.html#optional-tags If an element is a void element, non-attribute children nodes are ignored. Use this if no convenience creator exists.

Example
package main

import (
	"os"

	g "github.com/maragudk/gomponents"
)

func main() {
	e := g.El("div", g.El("span"))
	_ = e.Render(os.Stdout)
}
Output:

<div><span></span></div>

func Group added in v0.7.0

func Group(children []Node) Node

Group multiple Nodes into one Node. Useful for concatenation of Nodes in variadic functions. The resulting Node cannot Render directly, trying it will panic. Render must happen through a parent element created with El or a helper.

func If added in v0.13.0

func If(condition bool, n Node) Node

If condition is true, return the given Node. Otherwise, return nil. This helper function is good for inlining elements conditionally.

Example
package main

import (
	"os"

	g "github.com/maragudk/gomponents"
)

func main() {
	showMessage := true
	e := g.El("div",
		g.If(showMessage, g.El("span", g.Text("You lost your hat!"))),
		g.If(!showMessage, g.El("span", g.Text("No messages."))),
	)
	_ = e.Render(os.Stdout)
}
Output:

<div><span>You lost your hat!</span></div>

func Map added in v0.11.0

func Map[T any](ts []T, cb func(T) Node) []Node

Map a slice of anything to a slice of Nodes.

Example
package main

import (
	"os"

	g "github.com/maragudk/gomponents"
)

func main() {
	items := []string{"party hat", "super hat"}
	e := g.El("ul", g.Group(g.Map(items, func(i string) g.Node {
		return g.El("li", g.Text(i))
	})))
	_ = e.Render(os.Stdout)
}
Output:

<ul><li>party hat</li><li>super hat</li></ul>

func Raw

func Raw(t string) Node

Raw creates a text DOM Node that just Renders the unescaped string t.

Example
package main

import (
	"os"

	g "github.com/maragudk/gomponents"
)

func main() {
	e := g.El("span",
		g.Raw(`<button onclick="javascript:alert('Party time!')">Party hats</button> &gt; normal hats.`),
	)
	_ = e.Render(os.Stdout)
}
Output:

<span><button onclick="javascript:alert('Party time!')">Party hats</button> &gt; normal hats.</span>

func Rawf added in v0.20.0

func Rawf(format string, a ...interface{}) Node

Rawf creates a text DOM Node that just Renders the interpolated and unescaped string format.

Example
package main

import (
	"os"

	g "github.com/maragudk/gomponents"
)

func main() {
	e := g.El("span",
		g.Rawf(`<button onclick="javascript:alert('%v')">Party hats</button> &gt; normal hats.`, "Party time!"),
	)
	_ = e.Render(os.Stdout)
}
Output:

<span><button onclick="javascript:alert('Party time!')">Party hats</button> &gt; normal hats.</span>

func Text

func Text(t string) Node

Text creates a text DOM Node that Renders the escaped string t.

Example
package main

import (
	"os"

	g "github.com/maragudk/gomponents"
)

func main() {
	e := g.El("span", g.Text("Party hats > normal hats."))
	_ = e.Render(os.Stdout)
}
Output:

<span>Party hats &gt; normal hats.</span>

func Textf added in v0.4.0

func Textf(format string, a ...interface{}) Node

Textf creates a text DOM Node that Renders the interpolated and escaped string format.

Example
package main

import (
	"os"

	g "github.com/maragudk/gomponents"
)

func main() {
	e := g.El("span", g.Textf("%v party hats > %v normal hats.", 2, 3))
	_ = e.Render(os.Stdout)
}
Output:

<span>2 party hats &gt; 3 normal hats.</span>

type NodeFunc

type NodeFunc func(io.Writer) error

NodeFunc is a render function that is also a Node of ElementType.

func (NodeFunc) Render

func (n NodeFunc) Render(w io.Writer) error

Render satisfies Node.

func (NodeFunc) String added in v0.2.0

func (n NodeFunc) String() string

String satisfies fmt.Stringer.

func (NodeFunc) Type added in v0.11.0

func (n NodeFunc) Type() NodeType

Type satisfies nodeTypeDescriber.

type NodeType added in v0.11.0

type NodeType int

NodeType describes what type of Node it is, currently either an ElementType or an AttributeType. This decides where a Node should be rendered. Nodes default to being ElementType.

Directories

Path Synopsis
Package components provides high-level components and helpers that are composed of low-level elements and attributes.
Package components provides high-level components and helpers that are composed of low-level elements and attributes.
examples
Package html provides common HTML elements and attributes.
Package html provides common HTML elements and attributes.
Package http provides adapters to render gomponents in http handlers.
Package http provides adapters to render gomponents in http handlers.
internal
assert
Package assert provides testing helpers.
Package assert provides testing helpers.
Package svg provides common SVG elements and attributes.
Package svg provides common SVG elements and attributes.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL