Skip to main content
FlowFn
IntegrationsTemplatesPricingDocsBlogSign inStart free
All documentation

Templates — show your data in HTML

UpdatedJun 13, 2026Reading time2 min read

What are templates?

Templates let you bind data straight into your HTML — no manual DOM code. Interpolate values with {{ … }}, repeat blocks with ff-each, and show/hide sections with ff-if. Expressions are plain JavaScript and can use anything your JS tab defines, plus the flowfn SDK.

Interpolation

<h1>{{ storeName }}</h1>
<p>{{ items.length }} items · {{ formatPrice(total) }}</p>
  • Works in text and in attribute values; output is HTML-escaped automatically, so interpolated data can never inject markup.
  • If an expression fails (an undefined variable, a typo), the literal {{ … }} text stays — your page never blanks out.
  • Content inside <pre> and <code> is left alone, so code samples display as written.

Loops

<template ff-each="(row, i) in flowfn.data.get('products')">
  <div class="card">
    <h3>{{ i + 1 }}. {{ row.name }}</h3>
    <p>{{ row.price }}</p>
  </div>
</template>
  • The <template> content is cloned once per array element. row in expr works too if you don't need the index.
  • Any array works — a data sheet via flowfn.data.get(…), a variable from your JS, or an inline expression (filter, sort, slice it first if you like).
  • Loops nest: an inner ff-each sees the outer loop's variables.

Conditionals

<template ff-if="flowfn.data.get('products').length === 0">
  <p>Nothing here yet — add your first product.</p>
</template>

Re-rendering

  • Data sheets re-render automatically — after flowfn.data.insert / update / delete / fetch, every template refreshes on its own.
  • Changed one of your own variables? Call flowfn.render() to refresh.

Raw HTML (escape hatch)

<div ff-html="renderUI()"></div>

ff-html sets the element's innerHTML unescaped from your expression — handy for a function that builds markup. Because nothing is escaped, only feed it markup you constructed yourself; for anything touched by visitor input, stick to {{ … }}.

Good to know

  • Templates run in the editor preview and on the published site identically.
  • Reusable components compose with templates: <template ff-each="row in …"><component name="card" title="{{ row.name }}" /></template> passes each row into the component. Inside a loop, write component props with double braces ({{ row.x }}) — single-brace {expr} props evaluate outside the loop and can't see row. Component bodies may contain their own ff-each / ff-if blocks.
  • Props are strings — pass fields (title="{{ row.name }}"), not whole objects. Inside a component body, bare {{ title }} is a prop slot, while dotted or complex expressions ({{ row.name }}, {{ row.price + 1 }}) evaluate against the surrounding loop directly — so a component used inside ff-each can read the whole row without any props.
  • Keys/triggers attach after render as usual; give looped elements stable classes if you bind them.

Spotted an issue or have feedback?

support@flowfn.com
Back to docs hub →