Templates#

The top-level templates option describes a few key fields, such as url which are evaluated by nunjucks.

checks are also evaluated as nunjucks templates.

Additional templates can be defined and imported for reuse as blocks or macros in other templates or checks.

Context#

Each template gets an object of this form:

{
  "config": { "forms": { "a-form-key": {} } },
  "data": { "a-form-key": { "some-data-data": "from_form" } }
}

Special Templates#

A few well-known template names and patterns are used globally.

url#

The templates.url field should generate a valid URL. All whitespace should be escaped (e.g. use " " | urlencode to get %20), as any remaining will be removed.

submit_button#

Markdown to show on the submit button, if all checks and schema validation are successful. If this evaluates to the empty string, no submit button will be shown.

submit_target#

The target for the submit_button. If an empty string, the default behavior of replacing the current page will be used.

  • use _blank to open a new browser tab

  • use the name of an <iframe name="some-iframe"> to replace that iframe’s content

download_filename#

A filename to suggest for data: URLs when the submit_button is shown.

above_{form}#

A markdown message to show above a form, where form is a key from the root forms object.

below_{form}#

A markdown message to show below a form, where form is a key from the root forms object.

checks#

On each change of any form, each member of checks is evaluated, then has leading and trailing whitespace removed. If the remaining string is non-empty, the check is considered failed, and the result rendered as markdown and show in the checks section at the end of the form.

This is useful for implementing cross-cutting constraints that cannot be captured in JSON schema, such as validating unique property values in arrays, or values matching between two, unrelated schema.

{
  "checks": {
    "Unique names": [
      "{% for name, things in data.thing-list.things | default([]) | groupby('name') %}",
      "{% set dupes = things | length %}",
      "{% if dupes > 1 %}",
      "- [ ] {{ dupes }} things have the name _'{{ name }}'_",
      "{% endif %}",
      "{% endfor %}"
    ]
  }
}

For import purposes, checks are nested under the checks/ path, so must use ../ to access other templates.

{
  "templates": {
    "common": [
      "{% macro foo %}",
      "{% endmacro %}"
    ]
  },
  "checks": {
    "ok": [
      "{% import '../common' %}",
      "{{ foo() }}"
    ]
  }
}

Filters#

In addition to the built-in filters and the pythonic jinja2 compatibility layer, some custom filters are available by default, while format-specific can be lazily loaded.

filter

note

base64

encode a string as Base64, useful for encoding arbitrary data in URLs

from_entries

build an object from [key,value] pairs with Object.entries

prune

recursively remove null objects and empty arrays and objects, useful in TOML

to_json ff

build a JSON string. options: indent=2

from_json ff

parse JSON string

to_toml ff

build a TOML string

from_toml ff

parse a TOML string

to_yaml ff

build a YAML string

from_yaml ff

parse a YAML string options: see yaml docs

Format Filters#

As urljsf already provides support for loading JSON, TOML, YAML as needed, the parse/serialize functions of the underlying JS libraries may also be enabled for templates, and lazily loaded before use. To load all of them:

{
  "nunjucks": {
    "filters": ["toml", "json", "yaml"]
  }
}