Skip to content

creamsensation/gox

Repository files navigation

GOX

Write reusable HTML in pure Go

package app

import . "github.com/creamsensation/gox"

func Page() string {
    return Render(
        Html(
            Lang("en"),
            Head(
                Title(Text("Example app")),
                Meta(Name("viewport"), Content("width=device-width,initial-scale=1.0")),
            ),
            Body(
                H1(Text("Example page")),
                P(Text("Example paragraph")),
            ),
        ),
    )
}

Main reason to use GOX

If you love Go, as I do, you love power && simplicity, then GOX is just for you.


Feel free to test, submit issues, etc...


Features


Elements

You can create HTML structure with built-in elements or create your own with factory function.
Library should contains most of elements.

Html(
  Head(
    Title()
  ),
  Body(
    Div()
  ),
)

Attributes

If you need to add attribute to element. You can create your own attributes with factory function.
Library should contains most attributes.

Button(
  Type("submit"),
  CustomData("track", "submit-button"),
)

// data-*
CustomData("*", "...")

Shared

Some elements and attributes have same names, here comes shared nodes.
All shared nodes have default node type, which can be modified with modifier node.
Because of sharing, you need to use node for content, instead of writing simple string argument.
Shared nodes are: cite, data, form, label, slot, span, style, title.

Label(Text("E-mail"))
Style(Element(), Raw("body{background:red;}"))

Raw

Sometimes you need to write custom HTML, use styles, or anything else...

Raw("body{background:blue;}")
Raw("<div>raw custom</div>")

Text

Only purpose is to write text content.

Div(Text("Example"))

Fragment

The fragment has purpose to group nodes.

Fragment(
  Div(),
  Span(),
  H1(),
)

Modifiers

When you use shared nodes, sometimes you need to change node type, then you have to use modifiers.

Label(Attribute(), Text("example label"))
Style(Element(), Raw(".text{color:red;}"))

Functions

Render

Render function transforms GOX nodes to string.
You can use multiple nodes as arguments, it automatically wraps them with Fragment.

Render(
  Div(Text("example")),
)

Write

Write function transforms GOX nodes and write them as content to provided writer as bytes.

Write(
  w,
  Div(Text("example")),
)

Directives

Directives are functions, which can be used for various operations.

If

someCondition := ...

If(someCondition, Div(Text("render if condition is true")))

Range

someSlice := []int{1,2,3}

Range(someSlice, func(item int) Node {
  return Div(Text(item))
})

Factories

Custom element

Create custom reusable element.

SomeCustomElement := CreateElement("x-custom")
Render(SomeCustomElement(Text("example content")))

Custom attribute

Create custom reusable attribute.

SomeCustomAttribute := CreateAttribute[string]("x-custom")
Render(Div(SomeCustomAttribute("custom attribute conttent"), Text("example content")))

Plugins

Custom Go struct can be used as GOX plugin, exists only one rule, must have Node method, which return gox.Node interface.

type CustomPlugin struct {
  Value string
}

func (p CustomPlugin) Node() gox.Node {
  return Div(Text(p.Value))
}

Render(
  Html(
    Body(
      CustomPlugin{ Value: "example" },
    )
  ) 
)

Components

Power of GOX approach is to create simple reusable components like React, Svelte, etc...

func UiButton(content string) Node {
  return Button(
    Class("bg-blue-400", "text-white", "rounded"),
    Type("button"),
    CustomData("test", "test-id"),
    Text(content),
  )
}

FAQ

Why did I create the library?

I was tired of JS / TS ecosystem, so much bloat and I wanted something simple, yet powerful, like Go, for frontend.

What will be next steps?

I want to create the whole ecosystem, which will use GOX as primary view system