dom

package module
v0.0.9 Latest Latest
Warning

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

Go to latest
Published: Jan 22, 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

  • TinyGo Optimized: Avoids heavy standard library packages like fmt or net/http to keep WASM binaries small.
  • Direct DOM Manipulation: No Virtual DOM overhead. You control the updates.
  • ID-Based Caching: Efficient element lookup and caching strategy.
  • Memory Safe: Automatic event listener cleanup on Unmount.

📦 Installation

go get github.com/tinywasm/dom

âš¡ Quick Start

1. Global API vs Instance

tinywasm/dom provides two ways to interact with the DOM:

  • Global API: Quick and easy functions like dom.Get(id), dom.Mount(parent, comp). Most applications should use this.
  • Instance API: If you need multiple isolated DOM instances (e.g., for testing or multiple root contexts).
2. Go Component

Here is a simple "Counter" component example.

package main

import (
	"github.com/tinywasm/dom"
	. "github.com/tinywasm/fmt"
)

type Counter struct {
	id    string
	count int
}

func NewCounter(id string) *Counter {
	return &Counter{id: id}
}

func (c *Counter) HandlerName() string { return c.id }

func (c *Counter) RenderHTML() string {
	return Html(
		"<div id='", c.id, "'>",
			"<span id='", c.id, "-val'>", c.count, "</span>",
			"<button id='", c.id, "-btn'>Increment</button>",
		"</div>",
	).String()
}

// OnMount is called after HTML is injected.
func (c *Counter) OnMount() {
	// Use the global dom.Get() to find elements
	valEl, _ := dom.Get(c.id + "-val")
	btnEl, _ := dom.Get(c.id + "-btn")

	// Bind events using the Element interface
	btnEl.Click(func(e dom.Event) {
		c.count++
		valEl.SetText(c.count)
	})
}

func main() {
	dom.Mount("app", NewCounter("my-counter"))
	select {}
}

🎯 Event Delegation

For complex components (like Forms), you can use event delegation at the root level using e.TargetID() and e.TargetValue():

func (c *MyList) OnMount() {
    root, _ := dom.Get(c.HandlerName())
    
    // Catch clicks from any child button
    root.On("click", func(e dom.Event) {
        id := e.TargetID() // "list-item-1", "list-item-2", etc.
        // Handle logic...
    })
}

📚 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. tinywasm/fmt Helper: Quick guide for string conversions and manipulations.
  6. Advanced Patterns: Dynamic lists, decoupling, and performance tips.
  7. Comparison: TinyDOM vs. syscall/js, VDOM, and JS frameworks.

License

MIT

Documentation ¶

Index ¶

Constants ¶

This section is empty.

Variables ¶

This section is empty.

Functions ¶

func Log ¶ added in v0.0.7

func Log(v ...any)

Log provides logging functionality.

func Mount ¶ added in v0.0.7

func Mount(parentID string, component Component) error

Mount injects a component into a parent element.

func SetLog ¶ added in v0.0.7

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

SetLog sets the logging function.

func Unmount ¶ added in v0.0.7

func Unmount(component Component)

Unmount removes a component from the DOM.

Types ¶

type CSSRenderer ¶

type CSSRenderer interface {
	Component
	RenderCSS() string
}

CSSRenderer is an optional interface for components that need to inject CSS. Only used in backend SSR.

type Component ¶

type Component interface {
	// HandlerName returns the unique identifier of the component's root element.
	HandlerName() string

	// RenderHTML returns the full HTML string of the component.
	// The root element of this HTML MUST have the id returned by HandlerName().
	RenderHTML() string
}

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

type DOM ¶

type DOM interface {
	// Get retrieves an element by its ID.
	// It uses an internal cache to avoid repeated DOM lookups.
	// Returns the element and a boolean indicating if it was found.
	Get(id string) (Element, bool)

	// Mount injects a component into a parent element.
	// 1. It calls component.RenderHTML()
	// 2. It sets the InnerHTML of the parent element (found by parentID)
	// 3. It calls component.OnMount() to bind events
	Mount(parentID string, component Component) error

	// Unmount removes a component from the DOM (by clearing the parent's HTML or removing the node)
	// and cleans up any event listeners registered via the Element interface.
	Unmount(component Component)

	// 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 interface {

	// SetText sets the text content of the element.
	// Accepts variadic arguments that are concatenated without spaces.
	//
	// Examples:
	//   elem.SetText("Count: ", 42)              // -> "Count: 42"
	//   elem.SetText(D.Hello, " ", D.User)       // -> "Hello User" (localized)
	SetText(v ...any)

	// SetHTML sets the inner HTML of the element.
	// Accepts variadic arguments that are concatenated without spaces.
	// Supports format strings with % specifiers.
	//
	// Examples:
	//   elem.SetHTML("<div>", "content", "</div>")  // -> "<div>content</div>"
	//   elem.SetHTML("<h1>%v</h1>", 42)             // -> "<h1>42</h1>"
	//   elem.SetHTML("<span>%L</span>", D.Hello)    // -> "<span>Hello</span>" (localized)
	SetHTML(v ...any)

	// AppendHTML adds HTML to the end of the element's content.
	// Useful for adding items to a list without re-rendering the whole list.
	// Accepts variadic arguments that are concatenated without spaces.
	//
	// Examples:
	//   elem.AppendHTML("<li>", item, "</li>")
	//   elem.AppendHTML("<div class='%s'>%v</div>", "item", count)
	AppendHTML(v ...any)

	// Remove removes the element from the DOM.
	Remove()

	// AddClass adds a CSS class to the element.
	AddClass(class string)

	// RemoveClass removes a CSS class from the element.
	RemoveClass(class string)

	// ToggleClass toggles a CSS class.
	ToggleClass(class string)

	// SetAttr sets an attribute value.
	// Accepts variadic arguments that are concatenated without spaces.
	//
	// Examples:
	//   elem.SetAttr("id", "item-", 42)           // -> id="item-42"
	//   elem.SetAttr("href", "/page/", pageNum)   // -> href="/page/5"
	//   elem.SetAttr("title", D.Hello)            // -> title="Hello" (localized)
	SetAttr(key string, v ...any)

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

	// RemoveAttr removes an attribute.
	RemoveAttr(key string)

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

	// SetValue sets the value of an input/textarea/select.
	// Accepts variadic arguments that are concatenated without spaces.
	//
	// Examples:
	//   elem.SetValue("default value")
	//   elem.SetValue("Item ", 42)                // -> "Item 42"
	SetValue(v ...any)

	// Click registers a click event handler.
	// The handler is automatically tracked and removed when the component is unmounted.
	Click(handler func(event Event))

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

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

Element represents a DOM node. It provides methods for direct manipulation and event binding.

All content methods (SetText, SetHTML, AppendHTML, SetAttr, SetValue) accept variadic arguments and support multiple input types:

  • Strings: Concatenated without spaces
  • Numbers: Converted to strings
  • Format strings: Printf-style formatting with % specifiers
  • Localized strings: Using D.* dictionary for multilingual support

For more information about translation and multilingual support, see: https://github.com/tinywasm/fmt/blob/main/docs/TRANSLATE.md

Examples:

elem.SetText("Hello ", "World")           // -> "Hello World"
elem.SetHTML("<div>", "content", "</div>") // -> "<div>content</div>"
elem.SetAttr("class", "btn-", 42)         // -> "btn-42"
elem.SetText(D.Hello)                     // -> "Hello" (EN) or "Hola" (ES)
elem.SetHTML("<h1>%v</h1>", 42)           // -> "<h1>42</h1>"

func Get ¶ added in v0.0.7

func Get(id string) (Element, bool)

Get retrieves an element by its ID.

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 JSRenderer ¶

type JSRenderer interface {
	Component
	RenderJS() string
}

JSRenderer is an optional interface for components that need to inject JS. Only used in backend SSR.

Jump to

Keyboard shortcuts

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