2021-05-07 05:40:55 -07:00
|
|
|
# Tired of complex template languages?
|
2020-09-13 13:50:19 -07:00
|
|
|
|
2023-12-26 20:41:42 -08:00
|
|
|
Upstream: https://github.com/maragudk/gomponents
|
|
|
|
|
2022-10-17 05:09:37 -07:00
|
|
|
[![GoDoc](https://pkg.go.dev/badge/github.com/maragudk/gomponents)](https://pkg.go.dev/github.com/maragudk/gomponents)
|
2020-09-14 01:51:29 -07:00
|
|
|
|
2021-05-07 05:40:55 -07:00
|
|
|
Try view components in pure Go.
|
2020-09-13 13:50:19 -07:00
|
|
|
|
2021-05-07 05:40:55 -07:00
|
|
|
_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.
|
2020-09-21 07:30:29 -07:00
|
|
|
|
2021-05-07 05:40:55 -07:00
|
|
|
The API may change until version 1 is reached.
|
|
|
|
|
|
|
|
Check out [www.gomponents.com](https://www.gomponents.com) for an introduction.
|
2020-09-25 03:32:50 -07:00
|
|
|
|
2021-06-18 01:35:58 -07:00
|
|
|
Made in 🇩🇰 by [maragu](https://www.maragu.dk), maker of [online Go courses](https://www.golang.dk/).
|
|
|
|
|
2020-11-02 02:05:23 -08:00
|
|
|
## Features
|
|
|
|
|
2020-12-10 04:00:23 -08:00
|
|
|
- Build reusable view components
|
2020-11-16 03:38:24 -08:00
|
|
|
- Write declarative HTML5 in Go without all the strings, so you get
|
2020-11-02 02:05:23 -08:00
|
|
|
- Type safety
|
|
|
|
- Auto-completion
|
|
|
|
- Nice formatting with `gofmt`
|
2020-12-10 04:00:23 -08:00
|
|
|
- Simple API that's easy to learn and use (you know most already if you know HTML)
|
2023-05-11 01:06:23 -07:00
|
|
|
- Useful helpers like `Text` and `Textf` that insert HTML-escaped text, `Map` for mapping data to components,
|
|
|
|
and `If` for conditional rendering.
|
2020-11-02 02:05:23 -08:00
|
|
|
- No external dependencies
|
|
|
|
|
2020-09-21 07:30:29 -07:00
|
|
|
## Usage
|
|
|
|
|
|
|
|
Get the library using `go get`:
|
|
|
|
|
2023-05-11 01:06:23 -07:00
|
|
|
```shell
|
|
|
|
go get github.com/maragudk/gomponents
|
2020-09-21 07:30:29 -07:00
|
|
|
```
|
|
|
|
|
2020-12-10 04:00:23 -08:00
|
|
|
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:
|
2020-09-21 07:30:29 -07:00
|
|
|
|
|
|
|
```go
|
2020-09-23 13:05:59 -07:00
|
|
|
package main
|
2020-09-21 07:30:29 -07:00
|
|
|
|
|
|
|
import (
|
2020-09-23 13:05:59 -07:00
|
|
|
"net/http"
|
2020-09-21 07:30:29 -07:00
|
|
|
|
2020-09-23 13:05:59 -07:00
|
|
|
g "github.com/maragudk/gomponents"
|
2020-12-10 04:00:23 -08:00
|
|
|
c "github.com/maragudk/gomponents/components"
|
|
|
|
. "github.com/maragudk/gomponents/html"
|
2020-09-21 07:30:29 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
func main() {
|
2020-12-10 04:00:23 -08:00
|
|
|
_ = http.ListenAndServe("localhost:8080", http.HandlerFunc(handler))
|
2020-09-21 07:30:29 -07:00
|
|
|
}
|
|
|
|
|
2020-12-10 04:00:23 -08:00
|
|
|
func handler(w http.ResponseWriter, r *http.Request) {
|
|
|
|
_ = Page("Hi!", r.URL.Path).Render(w)
|
2020-09-21 07:30:29 -07:00
|
|
|
}
|
2020-09-23 13:05:59 -07:00
|
|
|
|
2020-12-10 04:00:23 -08:00
|
|
|
func Page(title, currentPath string) g.Node {
|
2020-12-10 04:13:10 -08:00
|
|
|
return Doctype(
|
2020-12-10 04:00:23 -08:00
|
|
|
HTML(
|
|
|
|
Lang("en"),
|
|
|
|
Head(
|
2021-05-05 00:53:19 -07:00
|
|
|
TitleEl(g.Text(title)),
|
2020-12-10 04:00:23 -08:00
|
|
|
StyleEl(Type("text/css"), g.Raw(".is-active{ font-weight: bold }")),
|
2020-09-23 13:05:59 -07:00
|
|
|
),
|
2020-12-10 04:00:23 -08:00
|
|
|
Body(
|
|
|
|
Navbar(currentPath),
|
2021-05-05 00:53:19 -07:00
|
|
|
H1(g.Text(title)),
|
2020-12-10 04:00:23 -08:00
|
|
|
P(g.Textf("Welcome to the page at %v.", currentPath)),
|
2020-09-23 13:05:59 -07:00
|
|
|
),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2020-12-10 04:00:23 -08:00
|
|
|
func Navbar(currentPath string) g.Node {
|
|
|
|
return Nav(
|
|
|
|
NavbarLink("/", "Home", currentPath),
|
|
|
|
NavbarLink("/about", "About", currentPath),
|
2020-09-23 13:05:59 -07:00
|
|
|
)
|
|
|
|
}
|
2020-12-10 04:00:23 -08:00
|
|
|
|
|
|
|
func NavbarLink(href, name, currentPath string) g.Node {
|
Simplify available elements (#55)
`a`, `form`, `img`, `input`, `label`, `option`, `progress`, `select`, and `textarea` are now just regular elements (without helper parameters), because:
- Sometimes the use case doesn't fit (`a` as anchor without href, for example)
- There's no reason these are special among the others, so streamlining them makes sense
Also added new attributes `action`, `alt`, `for`, `method` that I had somehow missed.
2020-12-10 05:20:33 -08:00
|
|
|
return A(Href(href), c.Classes{"is-active": currentPath == href}, g.Text(name))
|
2020-12-10 04:00:23 -08:00
|
|
|
}
|
2020-09-21 07:30:29 -07:00
|
|
|
```
|
|
|
|
|
2020-12-10 04:00:23 -08:00
|
|
|
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:
|
2020-10-29 04:03:43 -07:00
|
|
|
|
|
|
|
```go
|
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"net/http"
|
|
|
|
|
|
|
|
g "github.com/maragudk/gomponents"
|
2020-12-10 04:13:10 -08:00
|
|
|
c "github.com/maragudk/gomponents/components"
|
2020-12-10 04:00:23 -08:00
|
|
|
. "github.com/maragudk/gomponents/html"
|
2020-10-29 04:03:43 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
func main() {
|
2020-12-10 04:00:23 -08:00
|
|
|
_ = http.ListenAndServe("localhost:8080", http.HandlerFunc(handler))
|
2020-10-29 04:03:43 -07:00
|
|
|
}
|
|
|
|
|
2020-12-10 04:00:23 -08:00
|
|
|
func handler(w http.ResponseWriter, r *http.Request) {
|
|
|
|
_ = Page("Hi!", r.URL.Path).Render(w)
|
2020-10-29 04:03:43 -07:00
|
|
|
}
|
|
|
|
|
2020-12-10 04:00:23 -08:00
|
|
|
func Page(title, currentPath string) g.Node {
|
2020-12-10 04:13:10 -08:00
|
|
|
return c.HTML5(c.HTML5Props{
|
2020-12-10 04:00:23 -08:00
|
|
|
Title: title,
|
|
|
|
Language: "en",
|
|
|
|
Head: []g.Node{
|
|
|
|
StyleEl(Type("text/css"), g.Raw(".is-active{ font-weight: bold }")),
|
|
|
|
},
|
|
|
|
Body: []g.Node{
|
|
|
|
Navbar(currentPath),
|
2021-05-05 00:53:19 -07:00
|
|
|
H1(g.Text(title)),
|
2020-12-10 04:00:23 -08:00
|
|
|
P(g.Textf("Welcome to the page at %v.", currentPath)),
|
2020-10-29 04:03:43 -07:00
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-12-10 04:00:23 -08:00
|
|
|
func Navbar(currentPath string) g.Node {
|
|
|
|
return Nav(
|
|
|
|
NavbarLink("/", "Home", currentPath),
|
|
|
|
NavbarLink("/about", "About", currentPath),
|
2020-10-29 04:03:43 -07:00
|
|
|
)
|
|
|
|
}
|
2020-12-10 04:00:23 -08:00
|
|
|
|
|
|
|
func NavbarLink(href, name, currentPath string) g.Node {
|
Simplify available elements (#55)
`a`, `form`, `img`, `input`, `label`, `option`, `progress`, `select`, and `textarea` are now just regular elements (without helper parameters), because:
- Sometimes the use case doesn't fit (`a` as anchor without href, for example)
- There's no reason these are special among the others, so streamlining them makes sense
Also added new attributes `action`, `alt`, `for`, `method` that I had somehow missed.
2020-12-10 05:20:33 -08:00
|
|
|
return A(Href(href), c.Classes{"is-active": currentPath == href}, g.Text(name))
|
2020-12-10 04:00:23 -08:00
|
|
|
}
|
2020-10-29 04:03:43 -07:00
|
|
|
```
|
|
|
|
|
2020-09-21 07:30:29 -07:00
|
|
|
For more complete examples, see [the examples directory](examples/).
|
2020-12-10 04:00:23 -08:00
|
|
|
|
|
|
|
### What's up with the specially named elements and attributes?
|
|
|
|
|
2020-12-22 02:46:49 -08:00
|
|
|
Unfortunately, there are four main name clashes in HTML elements and attributes, so they need an `El` or `Attr` suffix,
|
2020-12-10 04:00:23 -08:00
|
|
|
respectively, to be able to co-exist in the same package in Go:
|
|
|
|
|
2020-12-22 02:46:49 -08:00
|
|
|
- `data` (`DataEl`/`DataAttr`)
|
2020-12-10 04:00:23 -08:00
|
|
|
- `form` (`FormEl`/`FormAttr`)
|
|
|
|
- `style` (`StyleEl`/`StyleAttr`)
|
|
|
|
- `title` (`TitleEl`/`TitleAttr`)
|