Examples

Interactive demos powered by talkDOM. Each example runs live on this page.

Basic GET + Apply

Click the button to fetch content from a partial and insert it into the receiver.

Content will appear here...
View Source
<div receiver="demo1">Content will appear here...</div>

<button sender="demo1 get: /partials/demos/hello.html apply: inner">
  Load Content
</button>

Append Content

Each click appends new content without removing existing content.

View Source
<div receiver="demo2"></div>

<button sender="demo2 get: /partials/demos/counter.html apply: append">
  Append Entry
</button>

Pipe Chaining

Fetch content with get: then pipe the result to apply: in a separate step.

Waiting for piped content...
View Source
<div receiver="demo3">Waiting for piped content...</div>

<button sender="demo3 get: /partials/demos/hello.html | demo3 apply: inner">
  Fetch & Apply via Pipe
</button>

Parallel Chains with Semicolons

Update two receivers simultaneously with independent chains separated by ;

Receiver A
Empty
Receiver B
Empty
View Source
<div receiver="demo4a">Empty</div>
<div receiver="demo4b">Empty</div>

<button sender="demo4a get: /partials/demos/hello.html apply: inner;
               demo4b get: /partials/demos/counter.html apply: inner">
  Load Both
</button>

Custom Methods

Register a custom toggle: method and use it in sender attributes.

This box will toggle its background color.
View Source
<script>
talkDOM.methods["toggle:"] = function(el, cls) {
  el.classList.toggle(cls);
};
</script>

<div receiver="demo5">
  This box will toggle its background color.
</div>

<button sender="demo5 toggle: bg-amber-400/20">
  Toggle Background
</button>

Loading State

This site registers a custom get:apply:loading: method to toggle a CSS class on the receiver during async operations.

This box dims while loading.
View Source
talkDOM.methods["get:apply:loading:"] = function(el, url, op, cls) {
  el.classList.add(cls);
  return talkDOM.methods["get:apply:"](el, url, op)
    .finally(function() { el.classList.remove(cls); });
};

<style>.is-loading { opacity: 0.5; }</style>

<div receiver="demo6a">This box dims while loading.</div>

<button sender="demo6a get: /partials/demos/hello.html apply: inner loading: is-loading">
  Load with Indicator
</button>

Confirm Before Action

Use confirm: to gate an action. Cancel aborts the chain.

Click the button and confirm to replace this content.
View Source
<div receiver="demo7">
  Click the button and confirm to replace this content.
</div>

<button sender="demo7 confirm: Replace content? | demo7 get: /partials/demos/hello.html apply: inner">
  Confirm & Load
</button>

Programmatic API

Dispatch messages from JavaScript with talkDOM.send().

Waiting for programmatic send...
View Source
<div receiver="demo8">Waiting for programmatic send...</div>

<button onclick="talkDOM.send('demo8 get: /partials/demos/hello.html apply: inner')">
  talkDOM.send()
</button>

Safe Text Output

Use text: to write a literal value. The receiver only accepts text updates.

Click a button to update this message.
View Source
<div receiver="notice" accepts="text">Ready</div>

<button sender="notice text: Saved successfully">Save</button>

Persist a Small Preference

The persist attribute saves successful updates in same-origin local storage. Choose a value, then refresh this page.

No preference selected yet.
View Source
<div receiver="preference" accepts="text" persist>Choose a theme</div>
<button sender="preference text: Preference saved as dark">Dark</button>

Replace the Receiver Element

Unlike inner, outer replaces the receiver itself. The response keeps the same receiver name so it can be targeted again.

Original receiver element. Load the replacement to swap this whole box.
View Source
<div receiver="card" accepts="outer">Original card</div>
<button sender="card get: /card.html apply: outer">Replace</button>

<!-- /card.html must return a replacement with receiver="card" -->
<div receiver="card" accepts="outer">New card</div>

Tips & Tricks

A few habits that make message-driven pages easier to maintain.

Choose the apply operation deliberately

inner replaces a receiver’s contents, append adds to a list, text writes literal text, and outer swaps the receiver element.

Use unique receiver names

A message updates every element with that receiver name. Reuse a name when you want coordinated updates; otherwise give each target its own name.

Use pipes for dependencies

A pipe passes one result to the next step. Separate independent work with a semicolon so both chains can start together.

Persist only non-sensitive UI state

Persisted markup is stored as plain text in same-origin local storage. Never put tokens, passwords, or private data there.

Delegate events for changing content

Listen on a stable ancestor such as document when controls may be replaced. talkDOM also bubbles talkdom:done and talkdom:error events.

Keep form bodies explicit

Core post: sends a request without serializing a form. Register a custom method for validated form or JSON payloads.

For arbitrary values, pass arguments directly instead of building a message string:

const notice = document.querySelector('[receiver="notice"]');
await talkDOM.deliver(notice, "text:", [userProvidedValue]);