Helpers

Helpers are the JavaScript functions your templates call to do things — send a query, open a preview, react to an answer, submit a form, show or hide the window. You reference them from HTML events as skdwn.instance.helpers.<name>(...). They are the behavioral counterpart to the Liquid templates: the template draws the button, the helper is what runs when it's clicked. In the file browser of the Advanced editor they live under Template Helpers (settings.extensions.helpers).

How a Helper Runs

Every helper is a plain function attached to skdwn.instance.helpers. Inside, it reaches the running assistant through the skdwn.instance object and drives the UI by updating state or creating results. The methods a helper leans on most:

Instance methodWhat it does
updateState(partial)Merge fields into the live state and re-render (e.g. { isLoading: true }).
createResult(result)Append a new exchange — { type, payload } — to the conversation.
retrieveResult(id) / updateResult(result)Read a result by id and write it back after mutating its payload.
clearResults()Wipe the stored conversation.
sendTrace(event, props?)Record an analytics event (feeds the dashboard).
getPreviousConversation()The prior turns, used to send conversational context.
executeStreamPrompt(request)Run a streamed query against the backend.
sendFormRequest(formType, values) / executeProxyRequest(id, body, cb)Submit a lead form / call a proxy endpoint.
stopQuery()Abort the in-flight streamed query.

Result type values you'll create: WELCOME (greeting + hints), FORM (a lead form), and ERROR (an error bubble). Reading and writing a result's payload is how helpers persist per-answer state such as a reaction.

Built-in Helpers

Below is every built-in, what it expects, and how it behaves. Signatures match the source; when a helper takes no arguments the parentheses are empty.

Query lifecycle

sendQuery()async, no arguments. Reads the current text from #skdwn-search-input. If it's empty it does nothing. Otherwise it flips state to { query, isLoading: true }, scrolls to the bottom, and streams the request to the backend. The request it builds carries:

  • userPrompt — the box's text.
  • previousConversation — the prior turns, only when

settings.usePreviousConversation is enabled; otherwise an empty string.

  • additionalContext — whatever the host page passed in startOptions.additionalContext.

On success it clears the box (query: ''), resets the textarea height, and closes any open tab. On failure it keeps the text so the user can retry, clears isLoading, logs the error, and pushes an ERROR result.

onChangeQuery(event) — wire to oninput on the textarea. Writes the field's value into state.query and auto-grows the textarea. Where the browser supports CSS field-sizing: content the growth is native; elsewhere (e.g. Firefox) it falls back to adjusting the height in JS.

onPressEnter(event) — wire to onkeydown on the textarea. Enter submits (calls sendQuery() and prevents the default newline); Shift+Enter inserts a line break so the box grows to a multi-line question.

stopQuery() — no arguments. Aborts a query that's currently streaming.

hintBoxClick(element) — pass the clicked element as this. Reads the suggested question from its data-hint attribute, drops it into the search box, calls sendQuery(), and traces a HintBoxClick event.

Conversation and reactions

showHints() — no arguments. Re-shows the greeting/hints by creating a fresh WELCOME result and traces ShowHints.

clearHistory() — no arguments. Clears stored results, empties state.results, creates a new WELCOME, and traces ClearHistory.

react(resultId, reactionType, element) — record a thumbs up/down on an answer. resultId is the id of the answer's result; reactionType is 'like' or 'dislike' (element is accepted for symmetry but unused). The toggle logic: clicking the same reaction again is a no-op; clicking the opposite one resets it to neutral. It traces a Reaction event and writes payload.reaction back onto the result.

Preview modal

openPreview(event, element) — open the image/document preview. Reads data-previewsrc (the source path segment) and data-title off the element, builds ${serviceURL}/api/public/assistants/${previewsrc} — appending the accesstoken as a query parameter when one is present — and shows it in the modal via { modalOpen: true, modalContent, modalTitle }.

data-* attributes are lowercased

The DOM lowercases dataset keys, so data-previewSrc in your Liquid is read as element.dataset.previewsrc. Match the casing the helper expects.

closePreview() — no arguments. Clears the modal ({ modalOpen: false, modalContent: '' }).

Window and layout

toggleMaximized() — no arguments. Toggles #skdwn-main-container between its minimized and maximized sizes and mirrors that in state.skdwnWindowState.

toggleShowFloatingWindow(show)show is a boolean. true hides the floating button, shows the window (restoring its last size, or forcing minimized when the floating action button is disabled), focuses the search box, and plays the open animation. false hides the window, marks it closed, and brings the button back.

handleScroll() — no arguments. Scrolls the conversation container (#skdwn-floating-window-main) to the bottom; helpers call it after adding content so the newest answer is visible.

Forms and proxies

showForm(formType)formType is the form's id. Sets activeForm: true and creates a FORM result (with a generated UUID) that renders that form.

sendForm(formType, event)async, wire to a form's onsubmit. Prevents the default submit, serializes the form's fields into a payload, marks the result as submitting, and calls sendFormRequest(formType, payload). On success the result is flagged submitted; on failure it pushes an ERROR result; either way it clears activeForm.

sendProxyForm(proxyId, event, callback)async, for forms that call a proxy endpoint. Prevents the default submit, serializes the fields, flips isLoading on, and calls executeProxyRequest(proxyId, payload, callback). If the proxy returns a response it's appended as a result; errors become an ERROR result.

Rendering helpers

materialIcon(parameters) — returns safe HTML for a Material icon. Unlike the event helpers, this one produces markup, so you use it as a Liquid filter (see Helpers are also filters). parameters accepts:

  • iconName — the ligature name (e.g. search, close).
  • size — CSS font-size (defaults to 16px).
  • iconStyle — an icon variant such as outlined or round (maps to material-icons-<style>).
{% assign icon = "" | buildIconParams %}   {# or pass an object you already have in scope #}
{{ icon | materialIcon }}

The value you pipe in becomes the parameters object, so in practice you call it with whatever object is in scope. Its output is already safe HTML — don't add | safe.

greet(parameters) — a tiny sample helper that returns JSON.stringify(parameters). It's there as a starting point when you add your own — open it, use Test code to pass sample JSON, and see the round-trip in the debug panel.

Calling a Helper

Bind helpers to DOM events straight from the Liquid:

<textarea id="skdwn-search-input"
          oninput="skdwn.instance.helpers.onChangeQuery(event)"
          onkeydown="skdwn.instance.helpers.onPressEnter(event)"></textarea>

<button onclick="skdwn.instance.helpers.sendQuery()">
  {{ 'ask' | t: 'Ask' }}
</button>

Pass data to a helper through data-* attributes and read them off the element with this:

<a href="#" onclick="skdwn.instance.helpers.openPreview(event, this)"
   data-title="{{ reference.title }}"
   data-previewSrc="{{ state.instance.config.key }}/tools/preview/{{ reference.id }}/{{ refPage }}">
  Preview
</a>

For a hint card, stash the question on data-hint and let hintBoxClick pick it up:

<button data-hint="{{ hint.text | sanitize }}"
        onclick="skdwn.instance.helpers.hintBoxClick(this)">
  {{ hint.text }}
</button>

Helpers Are Also Filters

Every helper — built-in and custom — is registered twice:

  1. As a method on skdwn.instance.helpers.<name>, for onclick/oninput/onsubmit.
  2. As a Liquid filter of the same name, for use inside {{ … }}.

Which one you use depends on what the helper does. Event helpers (sendQuery, react, openPreview, …) belong on DOM events. Helpers that return a value — like materialIcon, which returns HTML — are used as filters, where the piped value becomes the helper's first argument:

{{ someValue | myFormatter }}   {# equivalent to myFormatter(someValue) #}

This is why a custom helper you add for formatting can be dropped straight into {{ }} without any extra wiring.

Your Own Helpers

The Advanced editor lets you add custom helpers — JavaScript stored in settings.extensions.helpers. Each entry can be a single function or an object of functions; Seekdown evaluates them at startup and merges them onto skdwn.instance.helpers, so you call them exactly like the built-ins. If a helper fails to evaluate it's skipped (with a console warning) rather than breaking the widget.

// A helper named "trackClick"
(ref) => { window.analytics?.track('reference_click', { id: ref }); }
<a onclick="skdwn.instance.helpers.trackClick('{{ reference.id }}')">{{ reference.title }}</a>

Inside a custom helper you have the same instance API the built-ins use. To change what's on screen, call skdwn.instance.updateState({ ... }); to add a message, call skdwn.instance.createResult({ type: 'ERROR', payload: { reply: 'Something went wrong' } }); to log an analytics event, call skdwn.instance.sendTrace('MyEvent', { ... }).

Test before you save

Use Test code in the editor toolbar to run a helper with sample JSON parameters and inspect its return value in the debug panel — the fastest way to check a helper behaves before wiring it into a template.

Go Deeper

Contact us

Still need help?

Tell us what you want your website assistant to answer. We will help you map the right content, controls, and launch path.