Hlive
HLive is a server-side WebSocket based dynamic template-less view layer for Go.
Install / Use
/learn @SamHennessy/HliveREADME
HLive
Server-side virtual DOM
HLive is a server-side WebSocket based dynamic template-less view layer for Go.
HLive is a fantastic tool for creating complex and dynamic browser-based user interfaces for developers who want to keep all the logic in Go.
All the power and data available on the backend with the responsive feel of a pure JavaScript solution.
It's a great use case for admin interfaces and internal company tools.
Notice
The first version of the API is under active development. Change is likely. Your feedback is welcome.
Please help the project by building something and giving us your feedback.
Table of contents
- Quick Start Tutorial
- Examples
- Concepts
- Tag
- Attribute
- Tag Children
- Components
- Node
- Element
- Page
- PageSession
- PageServer
- Middleware
- PageSessionStore
- HTTP vs WebSocket Render
- Tree and Tree Copy
- WebSocket Render and Tree Diffing
- First WebSocket Render
- AutoRender and Manuel Render
- Local Render
- Differ
- Render
- HTML Type
- JavaScript
- Virtual DOM, Browser DOM
- Lifecycle
- Known Issues
- Inspiration
- Similar Projects
- TODO
- HHot
- Contributing
Quick Start Tutorial
Step 1: Static Page
Import HLive using the optional alias l:
package main
import l "github.com/SamHennessy/hlive"
Let's create our first page:
func home() *l.Page {
page := l.NewPage()
page.DOM.Body.Add("Hello, world.")
return page
}
Next we use a PageServer to add it to an HTTP router:
func main() {
http.Handle("/", l.NewPageServer(home))
log.Println("Listing on :3000")
if err := http.ListenAndServe(":3000", nil); err != nil {
log.Println("Error: http listen and serve:", err)
}
}
Your editor should add the extra imports http and log for you.
You can now run it, for example:
go run ./tutorial/helloworld/helloworld.go
In a browser go to http://localhost:3000 you should see this:

Step 2: Interactive Page
HLive is all about interactive content. We're going to add a text input field to let us type our own hello message.
We need to replace our existing home function. We need a string to hold our message:
func home() *l.Page {
var message string
Now we're going to create a Component. Component's are HTML tags that can react to browser events. We are going to base our Component on the input HTML tag.
input := l.C("input")
We want to set the input to a text type. We do this adding aAttrs map to our Component.
input.Add(l.Attrs{"type": "text"})
Here we add an EventBinding to listen to "keyup" JavaScript events. When triggered, the handler function will be called. Our handler will update message. It does this by using the data passed in the Event parameter.
input.Add(l.On("keyup", func(ctx context.Context, e l.Event) {
message = e.Value
}))
We create a new Page like before:
page := l.NewPage()
Here we add our input to the body but first we wrap it in a div tag.
page.DOM.Body.Add(l.T("div", input))
Next, we will display our message. Notice that we're passing message by reference. That's key for making this example work. We'll also add an "hr" tag to stop it being squashed todeather.
page.DOM.Body.Add(l.T("hr"))
page.DOM.Body.Add("Hello, ", &message)
Finally, we return the Page we created.
return page
}
Let's see that all together, but this time I'm going to use some shortcuts. Can you spot the differences?
func home() *l.Page {
var message string
input := l.C("input",
l.Attrs{"type": "text"},
l.OnKeyUp(func(ctx context.Context, e l.Event) {
message = e.Value
}),
)
page := l.NewPage()
page.DOM.Body.Add(
l.T("div", input),
l.T("hr"),
"Hello, ", &message,
)
return page
}
Run it and type something into the input. The page should update to display what you typed.

Examples
The examples can be run from the root of the project using go run <path_to_example>. For example:
go run _example/click/click.go
Simple
Click
Click a button see a counter update.
https://user-images.githubusercontent.com/119867/131120937-64091d27-3232-4820-ab20-e579c86cfb92.mp4
Hover
Hover over an element and see another element change
Diff Apply
Trigger a Diff Apply event when a DOM change is applied in the browser. Use it to trigger server side logic.
Advanced
Animation
_example/animation/animation.go
Create a continuously changing animation by chaining Diff Apply callbacks.
Clock
Push browser DOM changes from the server without the need for a user to interact with the page.
File Upload
_example/fileUpload/fileUpload.go
Use a file input to get information about a file before uploading it. Then trigger a file upload from the server when you're ready.
The file is uploaded via WebSocket as a binary (not base64 encoded) object.
Initial Sync
_example/initialSync/initialSync.go
Some browsers, such as FireFox, will not clear data from form fields when the page is reloaded. To the user there is data in the field and if they submit a form they expect that data to be recognised.
Initial sync is a client side process that will send this data to the server after a page refresh. You can check for this behavior in your event handlers.
This example also shows how to get multiple values from inputs that support that.
Local Render
_example/localRender/localRender.go
By default, all Components are rendered after each Event Binding that a user triggers.
You can disable this by turning Auto Render off for a component. You can then render that manually but this will rerender the whole page.
If you only want to re-render a single component, and it's children you can do that instead. It's easy to introduce subtle bugs when using this feature.
Session
An example of how to implement a user session using middleware and cookies. It also shows our to pass data from middleware to Components.
Using middleware in HLive is just like any Go app.
To Do List
A simple To Do list app.
URL Parameters
_example/urlParams/urlParams.go
Passing URL params to Components is not straightforward in HLive. Here is an example of how to do it.
This is due to the HLive having a two-step process of loading a page and Components are primarily designed to get data from Events.
Concepts
Tag
A static HTML tag. A Tag has a name (e.g., an <p></p>'s name is p). A Tag can have zero or more Attributes. A Tag can have child Tags nested inside it. A Tag may be Void, which means it doesn't have a closing tag (e.g., <hr>). Void tags can't have child Tags.
Attribute
An Attribute has a name and a value. (e.g., href="https://example.com" or disabled="").
CSS Classes
The HLive implementation of Tag has an optional special way to work with the class attribute. These types are all designed to make toggling CSS classes on and off easy.
HLive's ClassBool is a map[string]bool type. The key is a CSS class, and the value enables the class for rending if tr
