gomponents

package module
v0.22.0 Latest Latest
Warning

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

Go to latest
Published: Oct 3, 2024 License: MIT Imports: 4 Imported by: 0

README

Tired of complex template languages?

Logo

GoDoc Go codecov Go Report Card

Try HTML components in pure Go.

gomponents are HTML 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.

Made with ✨sparkles✨ by maragu.

Does your company depend on this project? Contact me at markus@maragu.dk to discuss options for a one-time or recurring invoice to ensure its continued thriving.

Features

Check out www.gomponents.com for an introduction.

  • Build reusable HTML components
  • Write declarative HTML 5 in Go without all the strings, so you get
    • Type safety from the compiler
    • Auto-completion from the IDE
    • Easy debugging with the standard Go debugger
    • Automatic formatting with gofmt/goimports
  • 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,
    • Raw and Rawf for inserting raw strings,
    • Map for mapping data to components and Group for grouping components,
    • and If/Iff for conditional rendering.
  • No external dependencies

Usage

go get github.com/maragudk/gomponents

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

package main

import (
	. "github.com/maragudk/gomponents"
	. "github.com/maragudk/gomponents/components"
	. "github.com/maragudk/gomponents/html"
)

func Navbar(authenticated bool, currentPath string) Node {
	return Nav(
		NavbarLink("/", "Home", currentPath),
		NavbarLink("/about", "About", currentPath),
		If(authenticated, NavbarLink("/profile", "Profile", currentPath)),
	)
}

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

Some people don't like dot-imports, and luckily it's completely optional.

For a more complete example, see the examples directory.

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

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

I've chosen one or the other based on what I think is the common usage. In either case, the less-used variant also exists in the codebase:

  • cite (Cite/CiteAttr, CiteEl also exists)
  • data (DataEl/Data, DataAttr also exists)
  • form (Form/FormAttr, FormEl also exists)
  • label (Label/LabelAttr, LabelEl also exists)
  • style (StyleEl/Style, StyleAttr also exists)
  • title (TitleEl/Title, TitleAttr also exists)

Documentation

Overview

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

The primary interface is a Node. It defines 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 Map, If, and Iff for mapping data to nodes and inserting them conditionally. There's also the Group type, which is a slice of Node-s that can be rendered as one Node.

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 Group added in v0.7.0

type Group []Node

Group a slice of Node-s into one Node, while still being usable like a regular slice of Node-s. A Group can render directly, but if any of the direct children are AttributeType, they will be ignored, to not produce invalid HTML.

Example
package main

import (
	"os"

	g "github.com/maragudk/gomponents"
)

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

<div></div><span></span>
Example (Slice)
package main

import (
	"os"

	g "github.com/maragudk/gomponents"
)

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

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

func Map added in v0.11.0

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

Map a slice of anything to a Group (which is just a slice of Node-s).

Example
package main

import (
	"os"

	g "github.com/maragudk/gomponents"
)

func main() {
	items := []string{"party hat", "super hat"}
	e := g.El("ul", 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>
Example (Index)
package main

import (
	"os"

	g "github.com/maragudk/gomponents"
)

func main() {
	items := []string{"party hat", "super hat"}
	var index int
	e := g.El("ul", g.Map(items, func(i string) g.Node {
		e := g.El("li", g.Textf("%v: %v", index, i))
		index++
		return e
	}))
	_ = e.Render(os.Stdout)
}
Output:

<ul><li>0: party hat</li><li>1: super hat</li></ul>

func (Group) Render added in v0.21.0

func (g Group) Render(w io.Writer) error

Render satisfies Node.

func (Group) String added in v0.21.0

func (g Group) String() string

String satisfies fmt.Stringer.

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 in the html package.

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 in the html package.

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 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. If it's important that the given Node is only evaluated if condition is true (for example, when using nilable variables), use Iff instead.

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 Iff added in v0.20.4

func Iff(condition bool, f func() Node) Node

Iff condition is true, call the given function. Otherwise, return nil. This helper function is good for inlining elements conditionally when the node depends on nilable data, or some other code that could potentially panic. If you just need simple conditional rendering, see If.

Example
package main

import (
	"os"

	g "github.com/maragudk/gomponents"
)

func main() {
	type User struct {
		Name string
	}
	var user *User

	e := g.El("div",
		// This would panic using just If
		g.Iff(user != nil, func() g.Node {
			return g.Text(user.Name)
		}),
	)

	_ = e.Render(os.Stdout)
}
Output:

<div></div>

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.
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.

Jump to

Keyboard shortcuts

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