dom

package module
v0.0.5 Latest Latest
Warning

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

Go to latest
Published: Dec 11, 2025 License: MIT Imports: 1 Imported by: 0

README ¶

TinyDOM

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

TinyDOM 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. HTML Setup

You need a basic HTML file with a container element (e.g., <div id="app">) where your Go application will mount.

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <script src="wasm_exec.js"></script>
    <script>
        const go = new Go();
        WebAssembly.instantiateStreaming(fetch("main.wasm"), go.importObject).then((result) => {
            go.run(result.instance);
        });
    </script>
</head>
<body>
    <!-- The root container for your application -->
    <div id="app"></div>
</body>
</html>
2. Go Component

Here is a simple "Counter" component example.

package main

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

// Counter is a simple component
type Counter struct {
	id    string
	count int
}

// NewCounter creates a new instance
func NewCounter(id string) *Counter {
	return &Counter{id: id}
}

// ID returns the component's unique ID
func (c *Counter) ID() string { return c.id }

// RenderHTML returns the initial HTML structure
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 binds event listeners
func (c *Counter) OnMount(dom tinydom.DOM) {
	valEl, _ := dom.Get(c.id + "-val")
	btnEl, _ := dom.Get(c.id + "-btn")

	btnEl.Click(func(e tinydom.Event) {
		c.count++
		// Update the counter
		valEl.SetText(c.count)
	})
}

// OnUnmount cleans up (optional, listeners are auto-removed)
func (c *Counter) OnUnmount() {}

func main() {
	// Initialize TinyDOM
	dom := tinydom.New(nil)
	
	// Mount the component to an existing element with id "app"
	dom.Mount("app", NewCounter("my-counter"))
	
	// Prevent main from exiting
	select {}
}

📚 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. TinyString 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 ¶

This section is empty.

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 {
	// ID returns the unique identifier of the component's root element.
	ID() string

	// RenderHTML returns the full HTML string of the component.
	// The root element of this HTML MUST have the id returned by ID().
	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.

func New ¶

func New(log func(v ...any)) DOM

New returns the platform-specific implementation of the DOM interface.

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>"

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
}

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