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
| Variable | Content |
|---|---|
{{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)) |
{{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, which display images stored in usercontent/. It replaces the simpler myImagesFolder/{{value}}.jpg pattern and adds proper thumbnail support.
Why thumbnail support matters
The straightforward approach - entering a slug like agastarche in your data cell and writing e.g. specimenScans/{{value}}.jpg as the template - still works and requires no migration. However, it has one significant limitation: the app has no way to distinguish between the full-size image and a smaller preview, so it treats them 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. That cached full-size image is then available for future offline viewing too.
Precaching and offline use
Set your thumbnail dimensions to something relatively small, but still useful when viewed - e.g 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 just is not fetched until the user explicitly opens the image. Once fetched it is cached and available offline thereafter.
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 disk | Role |
|---|---|
agastarche.jpg | Base image (or full-size when no full suffix is declared) |
agastarche_640.jpg | Thumbnail (e.g. 640px) - produced by your batch tool |
agastarche_2400.jpg | Large scan (e.g. 2400px) - 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 author enters only the slug (agastarche) in the data cell; the app builds the right path for each context automatically.
Syntax
{{img}}
{{img value}}
{{img (thumb "_640")}}
{{img (full "_2400")}}
{{img (thumb "_640") (full "_2400")}}
{{img value (thumb "_640") (full "_2400")}}
{{img (thumbPath data.thumbSlug)}}
{{img (fullPath data.fullSlug)}}The base value is the stem shared by both variants. 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 the helper in the template string itself - never inside:
images/{{img (thumb "_640") (full "_2400")}}.jpg ← correct images/{{img
(thumb "_640.jpg")
(full "_2400.jpg")
}}
← do not do this** You could break this rule in an advanced use case if you are using different file types for the full image (e.g. uncompressed PNG) and for the thumbnail (e.g. highly compressed WEBP).
Declaring variants:
| Parameter | Effect |
|---|---|
(thumb "_640") | Thumbnail = base + _640; full-size = base |
(full "_2400") | Full-size = base + _2400; thumbnail falls back to full-size |
(thumb "_640") (full "_2400") | Thumbnail = base + _640; full-size = base + _2400 |
(thumbPath data.thumbSlug) | Thumbnail stem is taken from a separate data column (thumbSlug) entirely |
(fullPath data.fullSlug) | Full-size stem is taken from a separate data column (fullSlug) entirely |
All arguments may appear in any order. When no variant subexpressions are given at all, {{img}} behaves identically to {{value}} - both thumbnail and full-size resolve to the same path. Existing plain-path templates require no migration.
Examples
Separate thumbnail and full-size by suffix (most common):
Author enters agastarche in the data cell.
images/{{img (thumb "_640") (full "_2400")}}.jpgThe app requests agastarche_640.jpg for the thumbnail preview and agastarche_2400.jpg when the user opens the full view.
Thumbnail suffix only (full-size is the base file):
images/img/{{img (thumb "_640")}}.jpgThumbnail → agastarche_640.jpg. Full-size → agastarche.jpg. Useful when you have one natural-resolution image and a smaller preview, without a separately exported large version.
Thumbnail and full-size with independent file names (stored in separate columns photo.thumb and photo.full):
images/img/{{img (thumbPath data.photo.thumb) (fullPath data.photo.full)}}.jpgUseful when your files do not share a common stem and the names are tracked in separate data columns rather than by suffix convention.
No thumbnail support - legacy style, still valid:
images/img/{{img}}.jpgBoth thumbnail and full-size resolve to images/agastarche.jpg. Functionally equivalent to the plain images/{{value}}.jpg approach.
Quick reference
| Template | Data cell | Full-size path | Thumbnail path |
|---|---|---|---|
images/{{img}}.jpg | agastarche | agastarche.jpg | agastarche.jpg |
images/{{img (full "_2400")}}.jpg | osmoxylon | osmoxylon_2400.jpg | osmoxylon_2400.jpg* |
images/{{img (thumb "_640")}}.jpg | cerbera | cerbera.jpg | cerbera_640.jpg |
images/{{img (thumb "_640") (full "_2400")}}.jpg | coix | coix_2400.jpg | coix_640.jpg |
* 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.
{{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
{{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
| Category | Input units |
|---|---|
| Length | um, mm, cm, m, km |
| Time | ms, s, min, h, d, y |
| Weight | mg, g, kg, t |
| Area | um2, 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
| Template | Raw cell value | Output |
|---|---|---|
{{unit "m"}} | 0.05 | 5 cm |
{{unit "m"}} | 1500 | 1.5 km |
{{unit "g"}} | 2500 | 2.5 kg |
{{unit "s"}} | 7200 | 2 h |
{{unit "cm2"}} | 10000 | 1 m² |
{{unit "m/s"}} | 2500 | 2.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²,m³.
Interval values
When a field contains two numbers (an interval), the helper is applied to each endpoint independently:
{{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:
{{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:
{{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:
maps/{{data.region}}.svgIf 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:
{{#if value}}Present in {{value}} region{{/if}}{{value}} {{#ifeq value "1"}}population{{else}}populations{{/if}}