Custom Export Themes
When Show & Tell exports a project as a Web Page or PDF, it renders your steps, photos, and videos through a theme — an HTML file with placeholder tokens. The app ships with three themes (Booklet, Gallery, and Journal), and with a Pro subscription you can import your own.
A theme is just HTML and CSS with a simple token syntax on top. If you’re comfortable editing those, you can make one. This page is the complete reference.
Download the starter theme
The quickest way in is our annotated starter theme:
Download the starter theme (right-click or long-press and save the file)
It’s a complete, working theme — you can import it into Show & Tell unchanged — and every section of it is commented: what each token does, how the loops work, and how the PDF fallbacks fit together. Save it, open it in your editor, and make it yours.
How themes work
A theme is a single, self-contained .html file. All CSS (and any JavaScript) must be inline.
At export time, Show & Tell copies your project’s media into a folder next to the rendered page, so themes reference media by relative path:
My Project/ ← zipped up for Web Page export
index.html ← your theme, with tokens filled in
media/
step-01-item-01.jpg
step-01-item-02.mp4
thumbs/
step-01-item-01.jpg
You never write those paths by hand — the media tokens (below) provide them.
Theme metadata
Start the file with a comment block that names your theme:
<!--showandtell-theme
name: Field Notes
author: Your Name
version: 1.0
description: A one-line description shown in the theme picker.
-->
Every field is optional (name falls back to the filename), and unknown fields are ignored.
Template syntax
Themes use a small mustache-style syntax:
| Syntax | Meaning |
|---|---|
{{project.name}} |
Insert a value, HTML-escaped |
{{{contentHTML}}} |
Insert a value raw — only for tokens documented as pre-rendered HTML |
{{#steps}} … {{/steps}} |
Section: repeats for each item of a list; for a true/false or single value, renders once when it’s present |
{{^meta.isPDF}} … {{/meta.isPDF}} |
Inverted section: renders when the value is missing, false, or an empty list |
{{! note to self }} |
Comment, stripped from the output |
A few things to remember:
- You can access values within objects using dot notation:
project.name,meta.exportDate. - Inside a section, names resolve against the current item first, then the surrounding scopes — so inside
{{#steps}},{{title}}is the step’s title, and{{meta.appName}}still works. - Missing values render as empty text, never an error. Your theme keeps working as new tokens are added in app updates.
- Very important: every
{{#…}}and{{^…}}needs its matching{{/…}}. Unbalanced sections are the one thing that makes a theme invalid.
Token reference
There are three top-level objects: project, steps, and meta.
project — the project itself
| Token | Value |
|---|---|
project.name |
Project name |
project.description |
Description text (project.hasDescription to test for one) |
project.status |
Draft, Published, or Archived |
project.createdDate, project.modifiedDate |
Localized long-format dates |
project.totalDuration |
Total of all step durations, e.g. “4h 30m” (project.hasDuration) |
project.stepCount, project.mediaCount |
Formatted counts |
project.coverImage |
The project’s last photo, with a src (project.hasCoverImage) |
steps — the list of steps, in order
Loop over it with {{#steps}} … {{/steps}}. Inside, each step has:
| Token | Value |
|---|---|
number |
1-based position |
title |
Step title |
content |
The step text as plain text (hasContent) |
contentHTML |
The step text pre-rendered as HTML — paragraphs and line breaks. Use triple braces: {{{contentHTML}}} |
duration |
Formatted duration (hasDuration) |
media |
The step’s attachments, in order (hasMedia) |
media — each step’s attachments
Loop with {{#media}} … {{/media}} inside a step. Each item has:
| Token | Value |
|---|---|
src |
Relative path, e.g. media/step-02-item-01.jpg |
thumbnailSrc |
Small preview under media/thumbs/ — may be absent, so wrap it in its own section |
isImage, isVideo, isAudio |
Exactly one is true |
mimeType, filename |
As stored |
meta — about the export
| Token | Value |
|---|---|
meta.appName |
“Show & Tell” |
meta.appVersion |
App version |
meta.exportDate |
Localized export date |
meta.isPDF |
True when rendering for PDF export |
Making your theme PDF-friendly
PDF export renders your theme in basically the same way, with meta.isPDF set to true. Three things you probably want to change for PDF export:
Swap out players. Depending on what you’re doing with the PDF, audio and video might not work. You can replace the default media players with a thumbnail and a caption instead:
{{#isVideo}}
{{^meta.isPDF}}
<video controls src="{{src}}"{{#thumbnailSrc}} poster="{{thumbnailSrc}}"{{/thumbnailSrc}}></video>
{{/meta.isPDF}}
{{#meta.isPDF}}
{{#thumbnailSrc}}<img src="{{thumbnailSrc}}" alt="">{{/thumbnailSrc}}
<p>Video ({{filename}}) not included in the PDF.</p>
{{/meta.isPDF}}
{{/isVideo}}
Add print CSS. Use break-inside: avoid on step sections and figures so they don’t split across pages, and hide anything interactive. The PDF renderer applies its own page margins, so skip large body margins in print:
@media print {
body { max-width: none; padding: 0; }
section.step, figure { break-inside: avoid; }
}
Don’t lay out with JavaScript. PDF rendering waits for images to load, not for scripts to run. (JavaScript is fine for web page exports.)
Importing and testing
Importing custom themes requires Show & Tell Pro.
- In Show & Tell, tap the Settings icon in the upper left corner, then tap Export Theme.
- Tap Import Theme… and select your
.htmlfile from Files. - Tap the eye icon next to any theme to preview it, rendered with a built-in sample project.
On import, Show & Tell checks that the file is 2 MB or smaller, reads as UTF-8 text, and parses and renders cleanly. Anything that passes is added to your theme list; anything that doesn’t is rejected with a message saying why.
Some things to keep in mind:
- Re-importing never overwrites. Importing “Field Notes.html” again gives you “Field Notes 2” — swipe left on the old version to delete it.
- Themes live on the device you imported them on. They aren’t synced with your projects, so import your theme on each device you export from.
- Previews run with JavaScript off, and a theme’s JS only ever runs in your own exported page.
Troubleshooting
| Message | What it means |
|---|---|
| “…could not be read as a UTF-8 HTML file.” | The file isn’t plain text in UTF-8. Re-save it from your editor with UTF-8 encoding. |
| “Themes must be 2 MB or smaller.” | The file is too big to load. |
| “The theme’s template markup is invalid: …” | A parse error, almost always an unbalanced section — a {{#…}} or {{^…}} without its matching {{/…}}. The rest of the message points at the tag. Watch out for tokens inside HTML comments: those are parsed too. |
Questions
Something you’re still not sure about, or you just want show off your latest theme? Either way, I’d love to hear from you.