For AI agents: the documentation index is at /docs/formbox/llms.txt. A Markdown version of this page is available at /docs/formbox/reference/liquid-template-language.md or by requesting it with the Accept: text/markdown header.
Formbox Docs

Liquid template language

How-to: Liquid print templates. Render API: $render.

A Liquid print template is HTML with Liquid tags. Expressions inside the tags are FHIRPath, not Liquid's own expression language. There are no Liquid filters: | is FHIRPath union.

%resource is the resource being rendered: a QuestionnaireResponse when you render a response, a Questionnaire when you render a blank form.

Output

{{ %resource.id }}
{{ %resource.item.count() }}

FHIRPath calls such as .first() and .not() work inside output tags.

Output is HTML-escaped by default (&, <, >, ", ' become entities), so a patient answer cannot inject markup. The exception is a variable created with a capture block — that value is emitted raw.

Conditionals

<!-- unknown directive: if -->

  {{ item.answer.value }}
<!-- unknown directive: elsif -->

  {{ item.text }}
<!-- unknown directive: else -->



Loops

{% for item in %resource.item %}
  <p>{{ item.text }}: {{ item.answer.value }}</p>
  <!-- unknown directive: if -->
<hr/>

%resource stays addressable inside the loop. Nested loops restore the outer forloop. Loop helpers include forloop.last and forloop.nextitem.

Assign and capture

{% assign n = %resource.item.count() %}
<p>{{ n }} items</p>

<!-- unknown directive: capture -->

  <h1>{{ %resource.questionnaire }}</h1>

{{ heading }}

Use capture when the block itself contains markup you want in the output. assign and for variables are escaped like normal output.

Unknown tags

An unknown tag, an if with no expression, or a for with no in is left in the output as literal text. A broken template shows itself in the result instead of failing the request.

Questionnaire extension

A questionnaire points at a template with http://hl7.org/fhir/StructureDefinition/instance-rendering:

{
  "url": "http://hl7.org/fhir/StructureDefinition/instance-rendering",
  "extension": [
    {
      "url": "purpose",
      "valueCoding": { "code": "print" }
    },
    {
      "url": "template",
      "valueCanonical": "http://forms.aidbox.io/Library/my-template"
    }
  ]
}
  • purpose — only valueCoding.code is read (print, summary, narrative, or patient). $render compares that code to the purpose parameter string.
  • template — valueCanonical, or valueReference to Library/<id> or a contained #id.

A template linked as narrative is rendered on QuestionnaireResponse submit into QuestionnaireResponse.text. The div must be valid XHTML.

Library resource

What the editor saves, and what $render reads:

{
  "resourceType": "Library",
  "id": "liquid-template-d0TSpgNl",
  "url": "http://forms.aidbox.io/Library/liquid-template-d0TSpgNl",
  "status": "active",
  "name": "Discharge summary",
  "type": { "coding": [{ "code": "logic-library" }] },
  "topic": [{
    "coding": [{
      "system": "http://forms.aidbox.io/CodeSystem/library-topic",
      "code": "liquid-template",
      "display": "Liquid template"
    }]
  }],
  "content": [{
    "contentType": "text/html",
    "data": "<base64 of the HTML>"
  }]
}
FieldUsed by
content[] with contentType: "text/html"$render — first match, base64 UTF-8. A content[].url or any other content type is ignored.
urlCanonical resolution from the questionnaire extension
nameUI label
topicEditor and Form Settings pickers (/Library?topic=…|liquid-template). Stamp it if you create Libraries via the API; otherwise they render but do not appear in the pickers.
status, typeNot read at render time

Last updated: