Skip to content

Dynamic content with templates

The Template column in Custom data definition table lets you transform a raw data value into a formatted display string before rendering. Templates use the Handlebars syntax: {{variableName}}.

Available variables

VariableContent
{{value}}The raw value of the current field (as a string)
{{taxon.name}}The leaf taxon name (e.g. Litoria aurea)
{{taxon.authority}}The taxon authority (e.g. (Lesson, 1829))
{{taxon.fullName}}Name + authority combined (e.g. Litoria aurea (Lesson, 1829))
{{taxon.ranks.[rank name].name}}The chosen rank's name (using ranks from Taxa definition), e.g. {{taxon.ranks.order.name}}Anura
{{taxon.ranks.[rank name].authority}}The chosen rank's taxonomic authority
{{taxon.ranks.[rank name].fullName}}The chosen rank's name + authority combined
{{data.*}}Any other data field from the same taxon row, accessed by data path
{{lat}}(geopoint only) The parsed latitude as a decimal number
{{long}}(geopoint only) The parsed longitude as a decimal number

Templates and the rendering pipeline

The template is applied to the data value before the type-specific renderer runs. Read Data types to see how templates work with each individual data type.

Templates support multilingual variants: Template:en, Template:fr, etc.

{{img}} - images and maps with thumbnail support

The img helper is the recommended way to reference image and map (do not confuse with mapregions) data types. It adds proper thumbnail support on top of what a plain path template can do.

How the full path is assembled

All image and map files must live inside the usercontent/ folder. Every path a template produces is resolved relative to that root - the app always prefixes it automatically, so you never write usercontent/ in the template itself.

Within that, a template using {{img}} has three distinct parts:

images/   {{img (thumb "*_640") (full "*_2400")}}   .jpg
│         │                                          │
│         └─ stem: resolved by {{img}}               └─ extension: static
└─ prefix: static

The prefix (folder path) and extension are static text you write once in the template cell. {{img}} is responsible only for the stem - the filename portion between them. For the example above, the files the app fetches are:

ContextFull path on disk
Thumbnailusercontent/images/banksia_serrata_640.jpg
Full-sizeusercontent/images/banksia_serrata_2400.jpg

This separation gives you full control over your folder layout and file format through the static parts of the template, while {{img}} takes care of switching between the thumbnail and full-size stems automatically.

A plain path template like specimenScans/{{value}}.jpg works on the same principle - the folder and extension are static, {{value}} provides the stem - but it cannot distinguish thumbnail from full-size, so the app treats both as the same file. {{img}} lifts that constraint.

Why thumbnail support matters

Without declared variants, the app has no way to distinguish between the full-size image and a smaller preview, so it treats both contexts as the same file. This means:

  • Offline precaching downloads the full-size file. If your images are high-resolution specimen scans or habitat photographs, precaching them all may consume hundreds of megabytes and make the app slow in use or to prepare offline.
  • No large-file workflow. There is no way to serve a very large file - a detailed scan, a high-resolution illustration - that stays off-device until the user explicitly opens it.

The img helper solves both problems. You declare which file is the thumbnail and which is the full-size. The app then precaches only the thumbnails - small enough to make the app fast and useful even on a slow connection or completely offline - while still serving the full-size image on demand when a user opens it while online. Once fetched, the full-size is cached and available offline thereafter.

Precaching and offline use

Set your thumbnail dimensions to something relatively small but still useful when viewed - 640 or 800 px on the long edge is a good target with proper compression. This keeps precaching fast. The full-size file has no size restriction; it is not fetched until the user explicitly opens the image.

How thumbnail files are produced

The img helper does not generate thumbnails - it resolves which filename to use at display time. You produce the thumbnail files yourself, once, with any batch image tool (ImageMagick, XnConvert, Lightroom export presets, or similar). The naming convention is entirely yours; you define it in the template. A common approach is a size suffix:

File on diskRole
usercontent/images/hakea_prostrata.jpgBase image (or full-size when no full pattern is declared)
usercontent/images/hakea_prostrata_640.jpgThumbnail (e.g. 640 px) - produced by your batch tool
usercontent/images/hakea_prostrata_2400.jpgLarge scan (e.g. 2400 px) - produced by your batch tool

Once the files are in place and the template is set, a single template definition covers every taxon in your dataset. The data author enters only the slug (hakea_prostrata) in their data cell; the app builds the right path for each context automatically.

Syntax

handlebars
{{img}}
{{img value}}
{{img (thumb "*_640")}}
{{img (full "*_2400")}}
{{img (thumb "*_640") (full "*_2400")}}
{{img value (thumb "*_640") (full "*_2400")}}
{{! _640 suffix for thumbnails and _2400 suffix for full size }}
{{img (thumb "sm_*")}}
{{img (thumb "sm_*") (full "lg_*")}}
{{! sm_ prefix for thumbnails and lg_ prefix for full size }}
{{img (thumb data.thumbSlug)}}
{{! thumbnail stem taken from column thumbSlug }}
{{img (full data.fullSlug)}}
{{! full-size stem taken from column fullSlug }}
{{img (thumb data.thumbSlug) (full data.fullSlug)}}
{{img (thumb "*_640") (full data.fullSlug)}}

The base value is the stem shared by both variants before any pattern is applied. When omitted, it comes from the current cell's value. When provided explicitly, it is an unquoted data path (e.g. data.otherCol).

The file extension is always written outside {{img}} as static text in the template string - never inside the helper:

handlebars
images/{{img (thumb "*_640")}}.jpg ← correct images/{{img (thumb "*_640.jpg")}}
← do not do this

The * placeholder

The key concept

* is a placeholder for the base value inside a pattern. The helper substitutes the actual base value in place of * at display time.

pattern "*_640"  +  base value "cerbera"     →  "cerbera_640"
pattern "sm_*"   +  base value "cerbera"     →  "sm_cerbera"

A pattern without * is treated as a complete stem on its own - the base value is ignored entirely and the pattern string (or the resolved value of a data column) is used as-is. This is how you point a variant at an independent filename or a separate data column.

Both (thumb …) and (full …) follow the same rules. Arguments may appear in any order inside {{img}}. When no variant subexpressions are given at all, {{img}} behaves identically to {{value}}. Plain-path templates require no migration.

When only (full) is declared and no (thumb) is present, the thumbnail falls back to the full variant rather than the bare base value, ensuring the template is always safe to use.

Examples

Each example shows:

  • nl_content Custom Data Definition - the Custom data definition Column name and the Template cell you fill in for that column's row.
  • Data sheet - what the data author actually types into the data column for each taxon.
  • Files on disk - which files must exist (paths are relative to usercontent/).
  • App resolves → - what the app constructs for each display context.

No variants - plain path

nl_content → Column namephoto
nl_content → Templateimages/{{img}}.jpg
Data sheet → photo columnosmoxylon
Files on diskimages/osmoxylon.jpg
→ Thumbnailusercontent/images/osmoxylon.jpg
→ Full-sizeusercontent/images/osmoxylon.jpg

No (thumb) or (full) declared. Both contexts resolve to the same file. Equivalent to the plain images/{{value}}.jpg approach.


Suffix thumbnail, base file as full-size

nl_content → Column namephoto
nl_content → Templateimages/{{img (thumb "*_640")}}.jpg
Data sheet → photo columncerbera
Files on diskimages/cerbera.jpg · images/cerbera_640.jpg
→ Thumbnailusercontent/images/cerbera_640.jpg
→ Full-sizeusercontent/images/cerbera.jpg

* is replaced by the base value, then _640 is appended. No (full) pattern is declared, so the full-size falls back to the bare base file.


Suffix thumbnail and suffix full-size (most common)

nl_content → Column namephoto
nl_content → Templateimages/{{img (thumb "*_640") (full "*_2400")}}.jpg
Data sheet → photo columnagastarche
Files on diskimages/agastarche_640.jpg · images/agastarche_2400.jpg
→ Thumbnailusercontent/images/agastarche_640.jpg
→ Full-sizeusercontent/images/agastarche_2400.jpg

Both variants are derived from the same base value by the same suffix rule. The base file (agastarche.jpg) does not need to exist on disk - only the two sized variants do.


Full-size only declared - thumbnail falls back to full

nl_content → Column namephoto
nl_content → Templateimages/{{img (full "*_2400")}}.jpg
Data sheet → photo columngrevillea_robusta
Files on diskimages/grevillea_robusta_2400.jpg
→ Thumbnailusercontent/images/grevillea_robusta_2400.jpg
→ Full-sizeusercontent/images/grevillea_robusta_2400.jpg

When only (full) is present, the thumbnail falls back to the full variant. Only one file is needed on disk. Use this when you want to declare the full-size naming explicitly but have no separate thumbnail export.


Prefix thumbnail, base file as full-size

nl_content → Column namephoto
nl_content → Templateimages/{{img (thumb "sm_*")}}.jpg
Data sheet → photo columnhakea
Files on diskimages/hakea.jpg · images/sm_hakea.jpg
→ Thumbnailusercontent/images/sm_hakea.jpg
→ Full-sizeusercontent/images/hakea.jpg

sm_ is prepended to the base value. Use this when your batch export tool names files by role prefix rather than by size suffix.


Prefix thumbnail and prefix full-size

nl_content → Column namephoto
nl_content → Templateimages/{{img (thumb "sm_*") (full "lg_*")}}.jpg
Data sheet → photo columnmelaleuca
Files on diskimages/sm_melaleuca.jpg · images/lg_melaleuca.jpg
→ Thumbnailusercontent/images/sm_melaleuca.jpg
→ Full-sizeusercontent/images/lg_melaleuca.jpg

Both variants use a prefix pattern. The base file does not need to exist.


Mixed - suffix thumbnail, prefix full-size

nl_content → Column namephoto
nl_content → Templateimages/{{img (thumb "*_640") (full "hires_*")}}.jpg
Data sheet → photo columneucalyptus_regnans
Files on diskimages/eucalyptus_regnans_640.jpg · images/hires_eucalyptus_regnans.jpg
→ Thumbnailusercontent/images/eucalyptus_regnans_640.jpg
→ Full-sizeusercontent/images/hires_eucalyptus_regnans.jpg

(thumb) and (full) are fully independent - each can use any pattern. Mix suffix and prefix freely to match whatever naming convention your tools produce.


Explicit base value from a different column

nl_content → Column namephoto
nl_content → Templateimages/{{img data.photo (thumb "*_640") (full "*_2400")}}.jpg
Data sheet → stem columnbanksia_serrata
Data sheet → photo columnspecimen_0187
Files on diskimages/specimen_0187_640.jpg · images/specimen_0187_2400.jpg
→ Thumbnailusercontent/images/specimen_0187_640.jpg
→ Full-sizeusercontent/images/specimen_0187_2400.jpg

Passing data.photo as the first argument overrides the implicit base - the patterns are applied to specimen_0187 instead of the current column's value. Use this when the image identifier lives in a different column from the one the template is attached to.


Data column overrides thumbnail stem - no *

nl_content → Column namephoto
nl_content → Templateimages/{{img (thumb data.thumbSlug) (full "*_2400")}}.jpg
Data sheet → photo columnacacia_pycnantha
Data sheet → thumbSlug columnacacia_pycnantha_thumb
Files on diskimages/acacia_pycnantha_thumb.jpg · images/acacia_pycnantha_2400.jpg
→ Thumbnailusercontent/images/acacia_pycnantha_thumb.jpg
→ Full-sizeusercontent/images/acacia_pycnantha_2400.jpg

data.thumbSlug contains no *, so its resolved value is used as the complete thumbnail stem - the base value (acacia_pycnantha) plays no part in building the thumbnail path. The full-size still applies the * pattern against the base. Use this when thumbnail filenames follow no predictable pattern and must be tracked individually per taxon.


Both variants from independent data columns - no * in either

nl_content → Column namephoto
nl_content → Templateimages/{{img (thumb data.thumbSlug) (full data.fullSlug)}}.jpg
Data sheet → thumbSlug columnlitoria_aurea_web
Data sheet → fullSlug columnlitoria_aurea_hires
Files on diskimages/litoria_aurea_web.jpg · images/litoria_aurea_hires.jpg
→ Thumbnailusercontent/images/litoria_aurea_web.jpg
→ Full-sizeusercontent/images/litoria_aurea_hires.jpg

Neither pattern contains *. Both stems are taken entirely from their respective data columns; the base value is not used at all. Use this when thumbnail and full-size filenames share no common stem and must be tracked separately per taxon.


Variants in separate subfolders via data columns

nl_content → Column namephoto
nl_content → Template{{img (thumb data.thumbPath) (full data.fullPath)}}.jpg
Data sheet → thumbPath columnthumbs/grevillea_robusta
Data sheet → fullPath columnscans/grevillea_robusta
Files on diskthumbs/grevillea_robusta.jpg · scans/grevillea_robusta.jpg
→ Thumbnailusercontent/thumbs/grevillea_robusta.jpg
→ Full-sizeusercontent/scans/grevillea_robusta.jpg

The data columns carry the subfolder as part of the value. There is no static prefix in the template - the entire path before the extension comes from the data. This lets you organise thumbnail and full-size files into completely separate directory trees, with each taxon's folders encoded in the data rather than hard-coded in the template.


Quick reference

All resolved paths are relative to usercontent/. The template prefix and extension columns show the static parts surrounding {{img …}} in the template cell.

Template prefix{{img …}} argumentsExtensionData column(s)→ Full-size stem→ Thumbnail stem
images/(none).jpgphoto = osmoxylonosmoxylonosmoxylon
images/(thumb "*_640").jpgphoto = cerberacerberacerbera_640
images/(full "*_2400").jpgphoto = grevillea_robustagrevillea_robusta_2400grevillea_robusta_2400
images/(thumb "*_640") (full "*_2400").jpgphoto = agastarcheagastarche_2400agastarche_640
images/(thumb "sm_*") (full "lg_*").jpgphoto = melaleucalg_melaleucasm_melaleuca
images/(thumb "*_640") (full "hires_*").jpgphoto = eucalyptus_regnanshires_eucalyptus_regnanseucalyptus_regnans_640
images/data.photo (thumb "*_640") (full "*_2400").jpgphoto = specimen_0187specimen_0187_2400specimen_0187_640
images/(thumb data.thumbSlug) (full "*_2400").jpgthumbSlug = acacia_pycnantha_thumb, photo = acacia_pycnanthaacacia_pycnantha_2400acacia_pycnantha_thumb
images/(thumb data.thumbSlug) (full data.fullSlug).jpgthumbSlug = litoria_aurea_web, fullSlug = litoria_aurea_hireslitoria_aurea_hireslitoria_aurea_web
(none)(thumb data.thumbPath) (full data.fullPath).jpgthumbPath = thumbs/grevillea_robusta, fullPath = scans/grevillea_robustascans/grevillea_robustathumbs/grevillea_robusta

† When only (full) is declared and no (thumb) is present, the thumbnail falls back to the full variant.

{{unit}} - automatic unit scaling

The unit helper takes a numeric value and a unit of measurement, then automatically scales the output to the most readable unit in the same category. This is strongly recommended for all numeric measurement fields - it lets you store data in a consistent base unit while displaying it in the most human-readable form. For example, in a mammal dataset your cell data could be entered as a typical or per-sex interval in grams, but would get automatically scaled, remaining grams for mice but automatically converted to tons for elephants.

Best practice

Store bare numbers in your data cells (e.g. 5) and use the template to format them (e.g. {{unit "m"}}). Do not enter 5 m or 8 kg in cells - that turns the value into text and disables numeric filtering.

Syntax

handlebars
{{unit "m"}}
{{! reads value from current context }}
{{unit data.myField "m"}}
{{! explicit field reference }}
{{unit "kg" "exact"}}
{{! current context value, no unit scaling }}
{{unit data.myField "kg" "exact"}}
{{! explicit field, exact mode }}

Supported units

CategoryInput units
Lengthum, mm, cm, m, km
Timems, s, min, h, d, y
Weightmg, g, kg, t
Areaum2, mm2, cm2, m2, km2
Volume (cubic)um3, mm3, cm3, m3, km3
Volume (liquid)ml, l

Combined units using / are supported for rates and densities - e.g. km/h, m3/s, kg/m2. Only the numerator is scaled; the denominator remains as specified.

Scaling examples

TemplateRaw cell valueOutput
{{unit "m"}}0.055 cm
{{unit "m"}}15001.5 km
{{unit "g"}}25002.5 kg
{{unit "s"}}72002 h
{{unit "cm2"}}100001 m²
{{unit "m/s"}}25002.5 km/s

Formatting rules

  • Numbers are rounded to a maximum of 2 decimal places with trailing zeros removed.
  • A non-breaking space is placed between the number and the unit symbol.
  • Area and volume units render with proper superscripts: cm², .

Interval values

When a field contains two numbers (an interval), the helper is applied to each endpoint independently:

handlebars
{{unit "m"}}
{{! interval [0.5, 1.2] → "50 cm – 1.2 m" }}
{{unit "m"}}
{{! interval [1.1, 1.5] → "1.1 m – 1.5 m" }}
{{unit "m"}}
{{! interval [3, 3]     → "3 m"            }}

If both endpoints resolve to the same number and unit, a single value is shown.

Exact mode

Pass "exact" as an additional argument to skip all unit scaling. Useful when you want to display data in the original unit regardless of magnitude, or when using a custom unit string not in the built-in dictionary:

handlebars
{{unit "kg" "exact"}}
{{! 0.005 → "0.005 kg" (no conversion to g) }}
{{unit "eggs" "exact"}}
{{! custom unit string }}

Render multiple columns in one place

Suppose you have a colName collum with collector's name and colNum column with collector number and you want to render them together. You can set the colNum hidden to data in Hidden, it will still keep it filtrable, just won't show up in the taxon card. Then you use this template on colName:

handlebars
{{value}} {{colNum}}

The value bears the current value of colName and the whole will render e.g. John Smith 457

Select a different map per taxon:

handlebars
maps/{{data.region}}.svg

If a taxon has region = africa, the SVG path becomes maps/africa.svg. An advanced use-case of Distribution maps with mapregions to show a different region-focused map in an otherwise global dataset.

Conditional content with Handlebars helpers:

handlebars
{{#if value}}Present in {{value}} region{{/if}}
handlebars
{{value}} {{#ifeq value "1"}}population{{else}}populations{{/ifeq}}

NaturaList documentation v1.5.0