dom

package module
v0.4.1 Latest Latest
Warning

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

Go to latest
Published: Feb 11, 2026 License: MIT Imports: 1 Imported by: 0

README

tinywasm/dom

Project Badges

Ultra-minimal DOM & event toolkit for Go (TinyGo WASM-optimized).

tinywasm/dom provides a minimalist, WASM-optimized way to interact with the browser DOM in Go, avoiding the overhead of the standard library and syscall/js exposure. It is designed specifically for TinyGo applications where binary size and performance are critical.

🚀 Features

  • Elm-Inspired Architecture: Component-local state with explicit updates (Model → Update → View)
  • Fluent Builder API: Chainable methods for concise, readable code
  • Hybrid Rendering: Choose DSL for dynamic components or string HTML for static ones
  • TinyGo Optimized: Avoids heavy standard library packages to keep WASM binaries <500KB
  • Direct DOM Manipulation: No Virtual DOM overhead. You control the updates.
  • ID-Based Caching: Efficient element lookup and caching strategy
  • Lifecycle Hooks: OnMount, OnUpdate, OnUnmount for fine-grained control

📦 Installation

go get github.com/tinywasm/dom

⚡ Quick Start

For a complete example including Elm architecture (Dynamic Components) and Static Components, check the following file:

👉 web/client.go

This file contains the reference implementation used for testing and demonstrations.

🎨 Fluent Builder API

The new fluent API allows chaining for concise, readable code:

dom.Div().
	ID("container").
	Class("flex items-center").
	Add(
		dom.Button().
			Text("Click me").
			On("click", handleClick),
		dom.Span().
			Text("Hello World"),
	).
	Render("app") // Terminal operation

Available builders: Div(), Span(), Button(), H1(), H2(), H3(), P(), Ul(), Li(), Input(), Form(), A(), Img()

🔄 Lifecycle Hooks

Components can implement optional lifecycle interfaces:

type MyComponent struct {
	*dom.Element
	data []string
}

// Called after component is mounted to DOM
func (c *MyComponent) OnMount() {
	c.data = fetchData()
	c.Update()
}

// Called after re-render (dom.Update)
func (c *MyComponent) OnUpdate() {
	fmt.Println("Component updated")
}

// Called before component is removed
func (c *MyComponent) OnUnmount() {
	// Cleanup resources
}

📝 Component Interface

All components must implement:

type Component interface {
	GetID() string
	SetID(string)
	RenderHTML() string  // OR Render() *Element
	Children() []Component
}

Two rendering options:

  1. RenderHTML() string - For static components (smaller binary)
  2. Render() *dom.Element - For dynamic components (type-safe, composable)

Components can implement either or both. DOM checks Render() first, falls back to RenderHTML().

🎯 Hybrid Rendering Strategy

Choose the right rendering method for each component:

Component Type Method Benefit
Static (no interactivity) RenderHTML() string Smaller binary, less overhead
Dynamic (interactive, state) Render() *dom.Element Type-safe, composable, fluent API

See the implementation examples in web/client.go to see both approaches in action.

🧩 Nested Components

Components can contain child components:

type MyList struct {
	*dom.Element
	items []dom.Component
}

func (c *MyList) Children() []dom.Component {
	return c.items
}

func (c *MyList) Render() *dom.Element {
	list := dom.Div()
	for _, item := range c.items {
		list.Add(item) // Components can be children
	}
	return list
}

When you call dom.Render("app", myList), the library will:

  1. Render the HTML
  2. Call OnMount() for MyList
  3. Recursively call OnMount() for all items

The same recursion applies to cleanup, ensuring all event listeners are cleaned up when a parent is replaced.

🎯 Event Handling

Event handling is integrated directly into the Builder API via On(eventType, handler).

🔧 Core API

Package Functions
// Rendering
dom.Render(parentID, component)  // Replace parent's content
dom.Append(parentID, component)  // Append after last child
dom.Update(component)            // Re-render in place

// Routing (hash-based)
dom.OnHashChange(handler)        // Listen to hash changes
dom.GetHash()                    // Get current hash
dom.SetHash(hash)                // Set hash
Element Helpers

Embedding *dom.Element provides these methods automatically:

type Counter struct {
	*dom.Element
	count int
}

// Chainable helpers
counter.Update()              // Trigger re-render
counter.GetID()               // Get unique ID
counter.SetID("my-id")        // Set custom ID

📚 Documentation

For more detailed information, please refer to the documentation in the docs/ directory:

  1. Specification & Philosophy: Design goals, architecture, and key decisions.
  2. API Reference: Detailed definition of DOM, Element, and Component interfaces.
  3. Creating Components: Guide to building basic and nested components.
  4. Event Handling: Using the Event interface for clicks, inputs, and forms.
  5. Advanced Patterns: Dynamic lists, decoupling, and performance tips.
  6. Comparison: TinyDOM vs. syscall/js, VDOM, and JS frameworks.

🆕 What's New in v0.2.0

  • Elm-inspired architecture - Component-local state with explicit updates
  • Fluent Builder API - Chainable methods (dom.Div().ID("x").Class("y"))
  • Hybrid rendering - Choose DSL or string HTML per component
  • Lifecycle hooks - OnMount, OnUpdate, OnUnmount
  • Auto-ID generation - All components get unique IDs automatically
  • Smaller binaries - TinyGo-optimized, <500KB for typical apps

📊 Performance

Binary Size (TinyGo WASM):

  • Simple counter app: ~35KB (compressed)
  • Todo list with 10 components: ~120KB (compressed)
  • Full application: <500KB (compressed)

Compared to standard library approach: 60-80% smaller binaries.

License

MIT

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Append added in v0.2.0

func Append(parentID string, component Component) error

Append injects a component AFTER the last child of the parent element.

func GetHash added in v0.0.11

func GetHash() string

GetHash gets the current hash.

func Log added in v0.0.7

func Log(v ...any)

Log provides logging functionality.

func OnHashChange added in v0.0.11

func OnHashChange(handler func(hash string))

OnHashChange registers a hash change listener.

func Render added in v0.2.0

func Render(parentID string, component Component) error

Render injects a component into a parent element.

func SetHash added in v0.0.11

func SetHash(hash string)

SetHash sets the current hash.

func SetLog added in v0.0.7

func SetLog(log func(v ...any))

SetLog sets the logging function.

func Update added in v0.2.0

func Update(component Component) error

Update re-renders a component.

Types

type CSSProvider added in v0.0.13

type CSSProvider interface {
	RenderCSS() string
}

CSSProvider is an optional interface for components that need to inject CSS.

type Component

type Component interface {
	GetID() string
	SetID(id string)
	RenderHTML() string
	Children() []Component
}

Component is the minimal interface for components. All components must implement this for both SSR (backend) and WASM (frontend).

type DOM

type DOM interface {
	// Render injecta un componente en un elemento padre.
	// 1. Llama a componente.Render() (si es ViewRenderer) o componente.RenderHTML()
	// 2. Establece el contenido del elemento padre (buscado por parentID)
	// 3. Llama a componente.OnMount() para enlazar eventos
	Render(parentID string, component Component) error

	// Append injecta un componente DESPUÉS del último hijo del elemento padre.
	// Útil para listas dinámicas.
	Append(parentID string, component Component) error

	// OnHashChange registra un listener para cambios en el hash de la URL.
	OnHashChange(handler func(hash string))

	// GetHash devuelve el hash actual de la URL (ej. "#help").
	GetHash() string

	// SetHash actualiza el hash de la URL.
	SetHash(hash string)

	// Update re-renderiza el componente en su posición actual en el DOM.
	Update(component Component) error

	// Log provides logging functionality using the log function passed to New.
	Log(v ...any)
}

DOM is the main entry point for interacting with the browser. It is designed to be injected into your components.

type Element

type Element struct {
	// contains filtered or unexported fields
}

Element represents a DOM element in the fluent Element API.

func A added in v0.2.0

func A() *Element

func Button added in v0.2.0

func Button() *Element

func Div added in v0.2.0

func Div() *Element

Factory functions

func Form added in v0.2.0

func Form() *Element

func H1 added in v0.2.0

func H1() *Element

func H2 added in v0.2.0

func H2() *Element

func H3 added in v0.2.0

func H3() *Element

func Img added in v0.2.0

func Img() *Element

func Input added in v0.2.0

func Input() *Element

func Li added in v0.2.0

func Li() *Element

func P added in v0.2.0

func P() *Element

func Span added in v0.2.0

func Span() *Element

func Ul added in v0.2.0

func Ul() *Element

func (*Element) Add added in v0.2.3

func (b *Element) Add(children ...any) *Element

Add adds one or more children to the element. Children can be *Element, Node, Component, or string.

func (*Element) Append added in v0.2.3

func (b *Element) Append(child any) *Element

Append adds a child to the element. Deprecated: use Add instead.

func (*Element) Attr added in v0.2.3

func (b *Element) Attr(key, val string) *Element

Attr sets an attribute on the element.

func (*Element) Children added in v0.2.3

func (b *Element) Children() []Component

Children returns the component's children (components only).

func (*Element) Class added in v0.2.3

func (b *Element) Class(class ...string) *Element

Class adds a class to the element.

func (*Element) GetID added in v0.2.3

func (b *Element) GetID() string

GetID returns the element's ID.

func (*Element) ID added in v0.2.3

func (b *Element) ID(id string) *Element

ID sets the ID of the element.

func (*Element) On

func (b *Element) On(eventType string, handler func(Event)) *Element

On adds a generic event handler.

func (*Element) Render added in v0.2.3

func (b *Element) Render(parentID string) error

Render renders the element to the parent. This is a terminal operation.

func (*Element) RenderHTML added in v0.2.3

func (b *Element) RenderHTML() string

RenderHTML renders the element to HTML string.

func (*Element) SetID added in v0.2.3

func (b *Element) SetID(id string)

SetID sets the element's ID.

func (*Element) Text added in v0.2.3

func (b *Element) Text(text string) *Element

Text adds a text node child.

func (*Element) Update added in v0.3.0

func (b *Element) Update() error

Update triggers a re-render of the component.

type Event

type Event interface {
	// PreventDefault prevents the default action of the event.
	PreventDefault()
	// StopPropagation stops the event from bubbling up the DOM tree.
	StopPropagation()
	// TargetValue returns the value of the event's target element.
	// Useful for input, textarea, and select elements.
	TargetValue() string
	// TargetID returns the ID of the event's target element.
	TargetID() string
}

Event represents a DOM event.

type EventHandler added in v0.2.0

type EventHandler struct {
	Name    string
	Handler func(Event)
}

EventHandler represents a DOM event handler in the declarative builder.

type IconSvgProvider added in v0.0.13

type IconSvgProvider interface {
	IconSvg() map[string]string
}

IconSvgProvider is an optional interface for components that provide SVG icons.

type JSProvider added in v0.0.13

type JSProvider interface {
	RenderJS() string
}

JSProvider is an optional interface for components that need to inject JS.

type Mountable added in v0.2.0

type Mountable interface {
	OnMount()
}

Mountable is an optional interface for components that need initialization logic.

type Reference added in v0.2.3

type Reference interface {

	// GetAttr retrieves an attribute value.
	GetAttr(key string) string

	// Value returns the current value of an input/textarea/select.
	Value() string

	// Checked returns the current checked state of a checkbox or radio button.
	Checked() bool

	// On registers a generic event handler (e.g., "click", "change", "input", "keydown").
	On(eventType string, handler func(event Event))

	// Focus sets focus to the element.
	Focus()
}

Reference represents a reference to a DOM node. It provides methods for reading and interaction.

type Unmountable added in v0.2.0

type Unmountable interface {
	OnUnmount()
}

Unmountable is an optional interface for components that need cleanup logic.

type Updatable added in v0.2.0

type Updatable interface {
	OnUpdate()
}

Updatable is an optional interface for components that need update logic.

type ViewRenderer added in v0.2.0

type ViewRenderer interface {
	Render() *Element
}

ViewRenderer returns a Node tree for declarative UI.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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