dom

package module
v0.10.1 Latest Latest
Warning

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

Go to latest
Published: May 31, 2026 License: MIT Imports: 1 Imported by: 10

README

tinywasm/dom

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

  • Lifecycle & DOM API: Render, Append, Update, Get, OnHashChange
  • Void Element Fix: Correctly renders <br>, <img>, <hr> without closing tags
  • 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, see:

👉 tinywasm/html — web/client.go

That file uses tinywasm/html for element builders and tinywasm/dom for lifecycle (Render, Update, Append).

tinywasm/dom focuses on DOM manipulation and component lifecycles. HTML element builders have been moved to their own packages:

🔄 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)
	String() string  // OR Render() *Element
	Children() []Component
}

Two rendering options:

  1. String() 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 String().

🎯 Hybrid Rendering Strategy

Choose the right rendering method for each component:

Component Type Method Benefit
Static (no interactivity) String() 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 := html.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
dom.Get(id)                      // Get a DOM Reference (value, focus, events)

// 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. Architecture & Builder API Guide: Comprehensive guide covering the isomorphic component model, the JSX-like builder, event handling, and optimization strategies for TinyGo.
  2. Agent Guide: Constraints and rules for agents (and humans) adding or modifying functionality — build split, error handling, naming, testing, and DOM boundary decisions.

🆕 What's New in v0.5.0

  • Major API Redesign - Builders moved to separate packages

  • Interface Standardized - RenderHTML() stringString() string (fmt.Stringer)

  • Internal Privatization - Cleaned up public API (privatized EventHandler, etc.)

  • Void Element Rendering - Correct HTML for <br>, <img>, <hr>

  • Auto-ID Generation - Simplified IDs without auto- prefix

  • Void Element Rendering - Correct HTML for <br>, <img>, <hr>

  • Fluent Builder API - Chainable methods (html.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

📊 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 GetDocumentAttr added in v0.9.0

func GetDocumentAttr(attr string) string

GetDocumentAttr reads an attribute from document.documentElement. Returns "" if the attribute is absent.

func GetHash added in v0.0.11

func GetHash() string

GetHash gets the current hash.

func LocalStorageAvailable added in v0.9.0

func LocalStorageAvailable() bool

LocalStorageAvailable reports whether localStorage is accessible in the current browser context. Returns false when blocked by iframe sandbox, privacy settings, or private mode. Used internally by all LocalStorage* functions and available as a public check.

func LocalStorageClear added in v0.9.0

func LocalStorageClear() error

LocalStorageClear removes all keys. Returns error if storage unavailable.

func LocalStorageDel added in v0.9.0

func LocalStorageDel(key string) error

LocalStorageDel removes a key. Returns error if storage unavailable.

func LocalStorageGet added in v0.9.0

func LocalStorageGet(key string) (string, error)

LocalStorageGet retrieves a value from window.localStorage. Returns ("", nil) — key absent, storage is functional. Returns ("", error) — storage unavailable.

func LocalStorageSet added in v0.9.0

func LocalStorageSet(key, value string) error

LocalStorageSet writes a key-value pair. Returns error if: storage unavailable, value > lsMaxValue, or budget exceeded.

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 SetDocumentAttr added in v0.9.0

func SetDocumentAttr(attr, value string)

SetDocumentAttr sets an attribute on document.documentElement (<html>). value=="" removes the attribute — consistent with GetDocumentAttr returning "" for absent attributes.

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)

Update re-renders a component.

Types

type Component

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

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

NOTE: If your struct embeds Element, embed it as a VALUE, not a pointer:

type MyComponent struct {
  Element       // ✅ Correct — never nil
  // NOT: *Element // ❌ Wrong — nil pointer causes panic in renderToHTML
}

This is because renderToHTML calls GetID() on every Component child before checking ViewRenderer.

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)

	// Get retrieves an element by ID.
	Get(id string) (Reference, bool)

	// 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 NewElement added in v0.10.1

func NewElement(tag string) *Element

NewElement creates an Element with the given HTML tag. Used by tinywasm/html, tinywasm/svg, tinywasm/image to build elements.

func (*Element) Add added in v0.2.3

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

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

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) For added in v0.8.0

func (b *Element) For(other *Element) *Element

For sets the for= attribute pointing to other's ID, auto-generating other's ID if it has none. Use for label/input pairing and aria-* references.

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) NoCloseTag added in v0.10.1

func (b *Element) NoCloseTag() *Element

NoCloseTag marks the element as self-closing (no closing tag rendered). Use for void HTML elements: br, hr, img, input, link, meta, etc.

func (*Element) On

func (b *Element) On(t string, h 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) SetID added in v0.2.3

func (b *Element) SetID(id string)

SetID sets the element's ID.

func (*Element) String added in v0.10.0

func (b *Element) String() string

String serializes the element tree to its string representation.

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()

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
	// TargetChecked returns the checked status of the event's target element.
	// Useful for checkbox and radio input elements.
	TargetChecked() bool
}

Event represents a DOM event.

type Mountable

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

	// SetValue sets element.value (inputs, textarea, select).
	SetValue(value string)

	// SetAttr calls element.setAttribute(key, value).
	// Use empty string for boolean attributes (e.g., SetAttr("disabled", "")).
	SetAttr(key, value string)

	// RemoveAttr calls element.removeAttribute(key).
	RemoveAttr(key string)

	// SetText sets element.textContent.
	// Safe for plain text — does not parse HTML.
	SetText(text 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.

func Get added in v0.0.7

func Get(id string) (Reference, bool)

Get retrieves an element by ID.

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.

Jump to

Keyboard shortcuts

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