Gopher logo

Tired of complex template languages?

Try HTML components in pure Go.

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

$ go get maragu.dev/gomponents

See gomponents on Github

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.

Video introduction

Into video? See this lightning talk from GopherCon 2021.

Components are just functions

Have a look at this component. If you know HTML, you know what it does. Easy, right?

import (
	. "maragu.dev/gomponents"
	. "maragu.dev/gomponents/html"
)

func Navbar() Node {
	return Nav(Class("navbar"),
		Ol(
			Li(A(Href("/"), Text("Home"))),
			Li(A(Href("/contact"), Text("Contact"))),
			Li(A(Href("/about"), Text("About"))),
		),
	)
}

Let's deduplicate a bit.

import (
	. "maragu.dev/gomponents"
	. "maragu.dev/gomponents/html"
)

func Navbar() Node {
	return Nav(Class("navbar"),
		Ol(
			NavbarItem("Home", "/"),
			NavbarItem("Contact", "/contact"),
			NavbarItem("About", "/about"),
		),
	)
}

func NavbarItem(name, path string) Node {
	return Li(A(Href(path), Text(name)))
}

Inline if

Sometimes you only want to show a component based on some condition. Enter If:

import (
	. "maragu.dev/gomponents"
	. "maragu.dev/gomponents/html"
)

func Navbar(loggedIn bool) Node {
	return Nav(Class("navbar"),
		Ol(
			NavbarItem("Home", "/"),
			NavbarItem("Contact", "/contact"),
			NavbarItem("About", "/about"),

			If(loggedIn,
				NavbarItem("Log out", "/logout"),
			),
		),
	)
}

func NavbarItem(name, path string) Node {
	return Li(A(Href(path), Text(name)))
}

PS: There's also Iff, which takes a callback function instead, to avoid those pesky nil pointer errors.

Map data to components

What if you have data and want to map it to components? No problem.

import (
	. "maragu.dev/gomponents"
	. "maragu.dev/gomponents/html"
)

type NavLink struct {
	Name string
	Path string
}

func Navbar(loggedIn bool, links []NavLink) Node {
	return Nav(Class("navbar"),
		Ol(
			Map(links, func(l NavLink) Node {
				return NavbarItem(l.Name, l.Path)
			}),

			If(loggedIn,
				NavbarItem("Log out", "/logout"),
			),
		),
	)
}

func NavbarItem(name, path string) Node {
	return Li(A(Href(path), Text(name)))
}

Styling

Want to apply CSS classes based on state? Use the Classes helper.

import (
	. "maragu.dev/gomponents"
	. "maragu.dev/gomponents/components"
	. "maragu.dev/gomponents/html"
)

type NavLink struct {
	Name string
	Path string
}

func Navbar(loggedIn bool, links []NavLink, currentPath string) Node {
	return Nav(Class("navbar"),
		Ol(
			Map(links, func(l NavLink) Node {
				return NavbarItem(l.Name, l.Path, l.Path == currentPath)
			}),

			If(loggedIn,
				NavbarItem("Log out", "/logout", false),
			),
		),
	)
}

func NavbarItem(name, path string, active bool) Node {
	return Li(A(Href(path), Text(name)), Classes{
		"navbar-item": true,
		"active":      active,
		"inactive":    !active,
	})
}

Sometimes you just want HTML

Miss those <tags> or need to inject HTML from somewhere else? Use Raw.

import (
	. "maragu.dev/gomponents"
	. "maragu.dev/gomponents/components"
	. "maragu.dev/gomponents/html"
)

type NavLink struct {
	Name string
	Path string
}

func Navbar(loggedIn bool, links []NavLink, currentPath string) Node {
	return Nav(Class("navbar"),
		Raw(`<span class="logo"><img src="logo.png"></span>`),

		Ol(
			Map(links, func(l NavLink) Node {
				return NavbarItem(l.Name, l.Path, l.Path == currentPath)
			}),

			If(loggedIn,
				NavbarItem("Log out", "/logout", false),
			),
		),
	)
}

func NavbarItem(name, path string, active bool) Node {
	return Li(A(Href(path), Text(name)), Classes{
		"navbar-item": true,
		"active":      active,
		"inactive":    !active,
	})
}

It's all just Go

Your editor helps you with auto-completion. It's type-safe. Nice formatting using gofmt. You can even use the debugger. And all common HTML elements and attributes are included!

Get started

$ go get maragu.dev/gomponents

Examples & templates

There’s an example app inside the gomponents repository. It’s a simple web server that serves two HTML pages using gomponents and TailwindCSS.

There’s also the gomponents starter kit, a full template repository for building a web app with gomponents, TailwindCSS, and HTMX.

Online HTML-to-gomponents converter

Piotr Kowalski created an online HTML-to-gomponents converter tool!

The end

See also the Github repository or the blog post that started it all.

PS: Buy the Official gomponents <marquee> Element here! 😁