Added
-
lvt-*attributes are now extensible:LiveTemplateClient.registerAttribute().
Adding an attribute used to mean forking this library — writing adom/*.ts
module, importing it intolivetemplate-client.ts, and inserting a call at the
right position in a hardcoded ~20-entry sequence. An app that wanted
lvt-x:copy-to-clipboardhad no supported way to get one.There are two layers. Most authors only need the declarative one: declare an
attribute name and get called per element.<button lvt-x:copy="{{.ShareURL}}">Copy link</button> <script src="{{ lvtClientScriptURL }}" defer></script> <script> LiveTemplateClient.registerAttribute({ attribute: "lvt-x:copy", onElementAdded(el, ctx) { el.addEventListener("click", () => navigator.clipboard.writeText(ctx.value)); }, }); </script>
The framework owns selector escaping, the DOM scan, per-element match
tracking, empty-value rejection, and sweeping elements that lost the attribute
or left the DOM — the sweep runs on every render, soonElementRemovedis
never deferred — so the three classic mistakes (no sweep, listeners stacking
on every render, a captured transport that dies at reconnect) are not
reachable from this layer.ctx.valueandctx.sendare live accessors, so a
listener wired once still reads the current attribute value and dispatches
through the current transport.Set
needsServerChannel: trueto getctx.send; the message routes through
the same path anlvt-on:clickaction uses, and the server cannot tell the
difference. No server-side registration, no new wire message type, no build
step.A
selectors+setup()/teardown()escape hatch covers handlers with
cross-element state; every built-in uses it, so an author is never on a lesser
API than the framework itself.Registration is static and late registration is supported: calling
registerAttributeafter the client has connected runs the handler against
the live DOM immediately, rather than waiting for the next render. That is the
only sequence available to a second<script>, becauseautoInit()has
already connected by the time one evaluates.Exported types:
AttributeHandler,DeclarativeHandler,LowLevelHandler,
ElementContext,SetupContext,SendFn,HandlerCategory.registerAttributeis deliberately unauthenticated, and grants no capability
a page script did not already have:window.liveTemplateClient.send()has
always been public, so any script with page access could already dispatch
arbitrary actions. Server-side authorization is unchanged and remains the
boundary that matters.Two limits worth knowing before you build on this. Registration is
append-only — there is nounregisterAttributeyet, so a dev server that
hot-reloads a handler bundle accumulates one live handler per reload; the
production<script defer>pattern, where a bundle evaluates once, is
unaffected. Anddispose()runs when the last client on the page
disconnects, because the registry is shared by all of them; per-client
cleanup belongs inteardown(root), which runs for each client as it goes.
Changed
- Every built-in attribute handler now runs through that same registry. The
hardcoded post-render call sequence and the matchingdisconnect()teardown
list are gone, replaced by a loop over registered handlers. No attribute
changed its spelling, semantics, or server-side treatment, and no template
needs an edit; all 824 pre-existing tests pass unmodified.
Installation
npm
npm install @livetemplate/client@0.25.1CDN
<script src="https://cdn.jsdelivr.net/npm/@livetemplate/client@0.25.1/dist/livetemplate-client.browser.js"></script>Related Releases
This release follows the LiveTemplate core library version 0.25.x
- Core Library: https://github.com/livetemplate/livetemplate
- CLI Tool: https://github.com/livetemplate/lvt
- Examples: https://github.com/livetemplate/examples