Documentation
¶
Overview ¶
Package bind provides element annotation helpers for tether. Each helper attaches a data-tether-* attribute to a Fluent element, telling the client JS runtime how to handle that element - which events to forward, what client-side behaviour to apply, or which reactive signals to bind.
All bindings are applied via Apply with composable Option values:
bind.Apply(button.Text("Delete"),
bind.OnClick("delete"),
bind.Confirm("Are you sure?"),
bind.Disable("Deleting..."),
)
This top-to-bottom style scales cleanly as behaviours are stacked and provides a single, consistent way to annotate elements.
Index ¶
- func Apply[E Settable[E]](el E, opts ...Option) E
- type Option
- func AutoFocus() Option
- func AutoScroll() Option
- func BindAttr(attr, signal string) Option
- func BindClass(class, signal string) Option
- func BindHide(signal string) Option
- func BindShow(signal string) Option
- func BindText(signal string) Option
- func BindValue(signal string) Option
- func Cloak() Option
- func Collect(selector string) Option
- func CollectSelected(selector string) Option
- func Confirm(message string) Option
- func CopyToClipboard(selector string) Option
- func Countdown(d time.Duration) Option
- func Data(key, value string) Option
- func Debounce(d time.Duration) Option
- func Disable(text string) Option
- func Draggable() Option
- func DropTarget(action string) Option
- func Editable(action string) Option
- func Event(eventType, action string) Option
- func EventData(key, value string) Option
- func FilterKey(key string) Option
- func FlashClass(class string) Option
- func FlashText(text string) Option
- func FocusTrap() Option
- func Hook(name string) Option
- func Hotkey(combo, action string) Option
- func Indicator(selector string) Option
- func Link() Option
- func MaxLength(n int, message string) Option
- func MinLength(n int, message string) Option
- func OnBlur(action string) Option
- func OnChange(action string) Option
- func OnClick(action string) Option
- func OnFocus(action string) Option
- func OnInput(action string) Option
- func OnKeyDown(action string) Option
- func OnLongPress(action string) Option
- func OnPaste(action string) Option
- func OnSubmit(action string) Option
- func OnSwipe(action string) Option
- func OnViewport(action string) Option
- func Optimistic(signal, value string) Option
- func OptimisticToggle(signal string) Option
- func Pattern(regex, message string) Option
- func Permanent() Option
- func Prefix(name string) Option
- func PreserveScroll() Option
- func PreventDefault() Option
- func PushSubscribe() Option
- func Required(message string) Option
- func Reset() Option
- func ScrollTo(selector string) Option
- func Selectable() Option
- func SetSignal(signal, value string) Option
- func Sortable(action string) Option
- func Throttle(d time.Duration) Option
- func Timer(name string) Option
- func TimerFormat(pattern string) Option
- func TimerOnComplete(action string) Option
- func TimerPrecision(d time.Duration) Option
- func ToggleAttr(attr string) Option
- func ToggleClass(class string) Option
- func ToggleSignal(signal string) Option
- func ToggleTarget(selector string) Option
- func Transition(name string) Option
- func Upload(action string) Option
- func UploadInput(selector string) Option
- func UploadProgress(action string) Option
- type Settable
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Option ¶
type Option struct {
// contains filtered or unexported fields
}
Option describes a single data attribute to apply to an element. Use with Apply for a top-to-bottom composition style when stacking multiple behaviours on one element:
bind.Apply(button.Text("Delete"),
bind.OnClick("delete"),
bind.Confirm("Are you sure?"),
bind.Disable("Deleting..."),
)
func AutoFocus ¶
func AutoFocus() Option
AutoFocus moves keyboard focus to this element after each server update morphs the DOM. Use this on the primary input in a form so the cursor returns there after each interaction.
func AutoScroll ¶ added in v0.2.3
func AutoScroll() Option
AutoScroll marks a scrollable container that should automatically scroll to the bottom after each morph. Use this on log viewers, streaming output, and chat feeds where new content appears at the bottom and the user should follow along. Unlike PreserveScroll which maintains the current position, AutoScroll always moves to the latest content.
func BindAttr ¶
BindAttr sets an HTML attribute to the signal's value. When the signal is falsy the attribute is removed entirely. Use this for dynamic attributes like "disabled", "aria-expanded", or "href".
func BindClass ¶
BindClass adds the CSS class when the named signal is truthy and removes it when falsy. Use this for conditional styling that reacts to server-pushed state without a full render cycle.
func BindHide ¶
BindHide is the inverse of BindShow: the element is hidden when the signal is truthy and visible when falsy.
func BindShow ¶
BindShow makes the element visible when the named signal is truthy and hidden when falsy. Visibility is toggled via CSS display - the element remains in the DOM either way.
func BindText ¶
BindText replaces the element's text content with the signal's current value whenever the server pushes an update via [tether.Session.Signal]. The signal name must match the key passed to Signal().
func BindValue ¶
BindValue binds a form element's value property (input, select, textarea) to a named signal. When the server pushes a new signal value, the form element's displayed value updates instantly.
func Cloak ¶
func Cloak() Option
Cloak hides the element until the tether runtime initialises. The client removes the attribute on startup, making the element visible. Use this to prevent a flash of unbound content - e.g. a signal-bound element that would briefly show its raw template text before the signal value is applied.
func Collect ¶
Collect adds a CSS selector that the client resolves at event time. Matched elements contribute their current value to Event.Data, keyed by the element's name or id attribute. Use this to send input values with a click or keydown event without wrapping in a form:
bind.Apply(button.New().Text("Send"),
bind.OnClick("chat.send"),
bind.Collect("#message-input"),
)
func CollectSelected ¶ added in v0.2.0
CollectSelected gathers the IDs of all selected items (those with the "tether-selected" class) within the container matched by selector. The IDs are included in the event data as a comma-separated "selected" key. Pair with OnClick on an action button:
bind.Apply(button.Text("Delete Selected"),
bind.OnClick("items.delete"),
bind.CollectSelected("#item-list"),
)
// In Handle:
ids := strings.Split(ev.Data["selected"], ",")
func Confirm ¶
Confirm shows a browser confirmation dialog before the event is sent. If the user cancels, the event is silently dropped.
func CopyToClipboard ¶ added in v0.2.0
CopyToClipboard copies the text content of the element matched by selector to the clipboard on click. No server round-trip - the copy happens entirely in the browser. Use this for "copy" buttons next to API keys, code snippets, or share URLs.
func Countdown ¶ added in v0.3.3
Countdown configures a timer to count down from the given duration instead of counting up from zero. When the timer reaches zero it stops automatically. Combine with TimerOnComplete to fire a server event when the countdown finishes.
func Data ¶
Data sets a custom data-tether-* attribute on the element. This is the escape hatch for attributes not covered by the built-in options.
func Debounce ¶
Debounce overrides the default input debounce delay for this element. The default (300ms, configurable via [tether.App].Client.DefaultDebounce) groups rapid keystrokes into a single event. Set a shorter duration for search-as-you-type, or a longer one for expensive operations. Panics if d is negative.
func Disable ¶
Disable replaces the element's text and disables it while the server processes the event. The original text and state are restored when the server responds. Prevents double-clicks and gives users visual feedback that something is happening.
func Draggable ¶ added in v0.2.0
func Draggable() Option
Draggable marks an element as draggable. Pair with EventData to attach identifying data (e.g. an item ID) that travels with the drag:
bind.Apply(card,
bind.Draggable(),
bind.EventData("id", card.ID),
)
func DropTarget ¶ added in v0.2.0
DropTarget marks an element as a valid drop zone. When a draggable element is dropped onto this target, the action fires with event data merged from both the dragged element and the target. Pair with EventData to identify the target:
bind.Apply(column,
bind.DropTarget("card.move"),
bind.EventData("column", "1"),
)
func Editable ¶ added in v0.2.0
Editable marks a contenteditable element and forwards its text content to the server when the element loses focus (blur). The action receives the edited text in ev.Value().
bind.Apply(span.Text("Click to edit").Attr("contenteditable", "true"),
bind.Editable("item.rename"),
)
func Event ¶
Event forwards an arbitrary DOM event to the server. Use this for event types not covered by the built-in options (OnClick, OnSubmit, etc.). The eventType is the standard DOM event name.
bind.Apply(el, bind.Event("dblclick", "open-editor"))
func EventData ¶
EventData attaches a static key-value pair to every event from this element. The pair appears in [tether.Event].Data alongside any values the client collects automatically (input value, form fields). Use this to carry context - like an item ID - with each click so the handler knows which item was acted on without maintaining server-side selection state.
func FilterKey ¶
FilterKey restricts an OnKeyDown binding to fire only for a specific key (e.g. "Enter", "Escape"). Other keys are silently ignored by the client and never reach the server.
func FlashClass ¶ added in v0.2.1
FlashClass temporarily adds a CSS class to the element after a client-side action succeeds. The class is removed after the configured flash duration. Use this for richer feedback like colour changes, icon swaps, or animations:
bind.Apply(btn,
bind.CopyToClipboard("#key"),
bind.FlashClass("copied"),
)
func FlashText ¶ added in v0.2.1
FlashText temporarily replaces the element's text content after a client-side action succeeds (e.g. clipboard copy). The original text is restored after the configured flash duration (Client.FlashDuration, default 2s). No server round-trip. Pair with CopyToClipboard or other client-side actions:
bind.Apply(btn,
bind.CopyToClipboard("#key"),
bind.FlashText("Copied!"),
)
func FocusTrap ¶
func FocusTrap() Option
FocusTrap constrains keyboard focus (Tab/Shift+Tab) to elements within this container. Use this for modals and drawers to prevent focus from escaping to elements behind the overlay - required for accessibility.
func Hook ¶
Hook attaches a named JS lifecycle hook to the element. Hooks are defined in application JS (e.g. hooks.js) and receive callbacks for mounted, updated, and destroyed events. Use this to integrate third-party JS libraries (charts, maps, editors) that need to initialise when the element appears, update when its data attributes change, and clean up when it is removed from the DOM.
func Hotkey ¶ added in v0.2.0
Hotkey registers a global keyboard shortcut. When the key combo is pressed anywhere on the page, the action fires as a normal tether event. The combo format is modifier keys joined with + followed by the key name: "ctrl+k", "escape", "shift+?", "ctrl+shift+p".
One hotkey per element. For multiple hotkeys, apply each to its own element:
bind.Apply(div.New(), bind.Hotkey("ctrl+k", "search.open"))
bind.Apply(div.New(), bind.Hotkey("escape", "modal.close"))
The client runtime builds a registry from [data-tether-hotkey] elements on init and after each morph. Lookups are O(1) per keypress with no CSS selector queries.
func Indicator ¶
Indicator shows a loading spinner or skeleton at the given CSS selector while the server processes the event. The indicator is removed when the server responds. Use this for actions where the user needs visual feedback in a different part of the page from the triggering element.
func Link ¶
func Link() Option
Link enables client-side navigation for anchor elements. Instead of a full page reload, the client intercepts the click, updates the browser URL via pushState, and sends a navigate event to the server. The server re-renders the active page and pushes a diff - only the changed content is updated, preserving scroll position and input state. Use this for navigation within a single tether handler. For links to a different handler (e.g. from /ws/ to /sse/), use a regular <a> tag so the browser performs a full page load.
func MaxLength ¶ added in v0.2.0
MaxLength prevents form submission if the field value exceeds n characters. The message is shown as a validation tooltip. Panics if n is negative.
func MinLength ¶ added in v0.2.0
MinLength prevents form submission if the field value is shorter than n characters. The message is shown as a validation tooltip. Panics if n is negative.
func OnBlur ¶
OnBlur forwards blur events to the server. Fires when the element loses keyboard focus. Useful for validating input on exit.
func OnChange ¶
OnChange forwards change events to the server. Unlike OnInput, this fires once when the user commits a value (leaving a text field, selecting a dropdown option, toggling a checkbox). The element's value is included in [tether.Event].Data["value"].
func OnClick ¶
OnClick forwards click events to the server. The action identifies which click this is (e.g. "delete", "save") so Handle can switch on it.
func OnFocus ¶
OnFocus forwards focus events to the server. Fires when the element receives keyboard focus (click, tab, or programmatic focus).
func OnInput ¶
OnInput forwards input events to the server with debouncing. The element's current value is included automatically in [tether.Event].Data["value"]. Debounce delay defaults to 300ms (configurable via [tether.App].Client.DefaultDebounce or per-element via Debounce).
func OnKeyDown ¶
OnKeyDown forwards keydown events to the server. The pressed key name (e.g. "Enter", "Escape", "ArrowUp") is available via [tether.Event].Key(). Combine with FilterKey to restrict which keys trigger the server event.
func OnLongPress ¶ added in v0.2.0
OnLongPress fires after a sustained touch (~500ms) on the element. Cancelled if the finger moves before the timeout. Common mobile alternative to right-click. Only fires on touch devices.
func OnPaste ¶ added in v0.2.0
OnPaste forwards paste events to the server. The pasted text is included in [tether.Event].Data["value"]. Use this for paste-to-search, paste-to-import, or paste-from-clipboard features.
func OnSubmit ¶
OnSubmit forwards form submissions to the server. All named fields inside the form are automatically collected into [tether.Event].Data so the handler can read them by name (ev.Data["email"], ev.Int("age")).
func OnSwipe ¶ added in v0.2.0
OnSwipe fires when the user swipes on the element. The swipe direction is included in ev.Data["direction"] as "left", "right", "up", or "down". Only fires on touch devices.
func OnViewport ¶
OnViewport fires when the element enters the visible viewport, using an IntersectionObserver internally. Place this on a sentinel element at the bottom of a list to implement infinite scroll - when the sentinel scrolls into view, the server loads the next page of data.
func Optimistic ¶
Optimistic sets a signal immediately on click AND sends the event to the server. The signal provides instant visual feedback while the server processes the event. If the server sends a different signal value in its response, the client updates to match - the server is always authoritative.
func OptimisticToggle ¶
OptimisticToggle flips a boolean signal immediately on click AND sends the event to the server. Like Optimistic but for boolean toggles - the signal flips instantly while the server processes the real state change.
func Pattern ¶ added in v0.2.0
Pattern prevents form submission if the field value does not match the regular expression. The message is shown as a validation tooltip.
func Permanent ¶
func Permanent() Option
Permanent excludes the element from DOM morphing. When idiomorph processes a server update, it skips elements marked permanent - their content, attributes, and children are preserved exactly as-is. Use this for elements with client-side state that must survive server updates (e.g. a video player, an interactive map, or a third-party widget that manages its own DOM).
func Prefix ¶
Prefix sets the event namespace for a component container. When the client JS sends an event from inside a prefixed container, it automatically prepends the prefix to the action. This allows components to use bare action names (e.g. "send") while the framework routes them via the full prefixed name (e.g. "shoutbox.send").
Apply Prefix to the element that wraps a mounted component's Render output:
bind.Apply(div.New(s.Chat.Render()), bind.Prefix("chat")).Dynamic("chat-section")
func PreserveScroll ¶ added in v0.2.0
func PreserveScroll() Option
PreserveScroll marks a scrollable container whose scroll position should survive DOM morphing. Without this, idiomorph may reset the scroll position when the container's content is updated. Use this on columns, chat feeds, or any scrollable region.
func PreventDefault ¶ added in v0.2.0
func PreventDefault() Option
PreventDefault suppresses the browser's default behaviour for the event. Use this with Event to handle events like contextmenu without the browser's native menu appearing:
bind.Apply(el, bind.Event("contextmenu", "menu.open"), bind.PreventDefault())
func PushSubscribe ¶
func PushSubscribe() Option
PushSubscribe marks a button for Web Push subscription. On click, the browser requests notification permission from the user and, if granted, subscribes via the service worker's PushManager. The subscription is sent to [tether.PushConfig].OnSubscribe so it can be stored for later use with [tether.Session.Push].
func Required ¶ added in v0.2.0
Required prevents form submission if the field is empty. The message is shown as a browser validation tooltip.
func Reset ¶
func Reset() Option
Reset clears all form fields after a successful submit. Useful for chat-style inputs where the form should be ready for the next message immediately after sending.
func ScrollTo ¶ added in v0.2.0
ScrollTo scrolls the matched element into view on click without a server round-trip. Uses smooth scrolling behaviour.
func Selectable ¶ added in v0.2.0
func Selectable() Option
Selectable marks a container for multi-select. Children with EventData "id" attributes become selectable items. Click selects one (deselects others), Ctrl/Cmd+click toggles, Shift+click selects a range. Selected items receive the "tether-selected" CSS class. Selection is purely client-side - no server round-trip per click. Use CollectSelected on an action button to gather the selected IDs when needed.
func SetSignal ¶
SetSignal sets a signal to a specific value on click. No server round-trip - the signal updates instantly on the client. Use this for tab selection, radio-style patterns, or any case where clicking an element should set a known value.
func Sortable ¶ added in v0.2.0
Sortable marks a container for within-container reordering. When a draggable element is dropped inside a sortable container, the action fires with the drop index in event data ("index"). This enables priority reordering within a list or column. Sortable containers are also valid drop targets - items can be dragged in from outside.
bind.Apply(todoColumn,
bind.Sortable("card.reorder"),
bind.EventData("column", "0"),
)
func Throttle ¶
Throttle sets a minimum interval between events from this element. Unlike Debounce which waits for a pause, Throttle fires the first event immediately and drops subsequent events until the interval elapses. Use this for scroll or resize handlers where you want regular updates without flooding the server. Panics if d is negative.
func Timer ¶ added in v0.3.3
Timer attaches a client-side timer to the element. The timer ticks entirely in the browser - no server goroutine, no WebSocket messages per tick. The server controls the timer by pushing signals:
- sess.Signal("name.running", true) starts the timer
- sess.Signal("name.running", false) pauses it
- sess.Signal("name", 0) resets the value
The element's text content is automatically bound to the formatted timer value - no separate BindText call is needed.
By default the timer counts up from zero at one-second precision with an auto-detected display format (ss, mm:ss, or hh:mm:ss). Combine with Countdown, TimerPrecision, TimerFormat, and TimerOnComplete to configure behaviour:
bind.Apply(el,
bind.Timer("quiz"),
bind.Countdown(30*time.Second),
bind.TimerOnComplete("quiz.expired"),
)
func TimerFormat ¶ added in v0.3.3
TimerFormat sets an explicit display format for the timer value. The default is "auto", which picks the shortest readable representation based on the current value (ss under a minute, mm:ss under an hour, hh:mm:ss beyond that).
Supported format tokens:
- hh:mm:ss hours, minutes, seconds
- mm:ss minutes, seconds
- ss seconds only
- mm:ss.S minutes, seconds, tenths
- mm:ss.SS minutes, seconds, hundredths
func TimerOnComplete ¶ added in v0.3.3
TimerOnComplete sets the event action fired back to the server when a countdown timer reaches zero. The event is sent as a standard tether event and appears in Handle with the given action name. Has no effect on count-up timers.
func TimerPrecision ¶ added in v0.3.3
TimerPrecision sets the tick interval for the timer. The default is one second. Use shorter intervals for stopwatch-style displays:
bind.TimerPrecision(100 * time.Millisecond) // tenths of a second
func ToggleAttr ¶
ToggleAttr toggles a boolean HTML attribute (e.g. "hidden", "disabled", "open") on click without a server round-trip.
func ToggleClass ¶
ToggleClass adds or removes a CSS class on click without a server round-trip. Useful for toggling visibility, active states, or themes entirely on the client. Combine with ToggleTarget to toggle a class on a different element.
func ToggleSignal ¶
ToggleSignal flips a boolean signal between true and false on click. No server round-trip - the signal updates instantly on the client. Combine with BindShow or BindClass for UI that toggles without network latency (dropdowns, accordions, dark mode).
func ToggleTarget ¶
ToggleTarget directs a ToggleClass or ToggleAttr at a different element identified by a CSS selector, rather than the clicked element.
func Transition ¶
Transition enables CSS enter/leave transitions on the element. The name maps to CSS class prefixes: {name}-enter-from, {name}-enter-to, {name}-leave-from, {name}-leave-to. When the element is added to the DOM, the enter classes are applied; when removed, the leave classes animate the element out before it is actually deleted.
func Upload ¶
Upload marks the element as a file upload trigger. Clicking it opens the browser's file picker. When files are selected, they are uploaded as a multipart POST to the server and delivered to [tether.UploadConfig].Handle. The action string identifies which upload this is (e.g. "avatar", "document") and appears in [tether.Upload].Action.
func UploadInput ¶
UploadInput provides a CSS selector for the file <input> element when it is not adjacent to the upload trigger in the DOM. By default the client looks for the nearest file input; use this when the input is elsewhere (e.g. hidden, in a different container).
func UploadProgress ¶
UploadProgress binds a <progress> element's value attribute to the upload progress for the named action. The client updates the value (0–100) as bytes are sent, giving users a visual progress bar.