Documents Template
This manual is intended for designers and developers who need to modify the HTML templates used to generate medical documents (treatment letters, aligner labels, order labels).
How the Template System Works
At a high level, the document generation process follows these steps:
- The selected HTML template is loaded.
- The system scans the HTML for tags (e.g.
[PATIENT_NAME],[INTRAORAL_FRONTAL_PHOTO], etc.). - Text tags are replaced with treatment data.
- Legend tags are replaced using the definitions inside the HTML comment block.
- Special tags are converted into embedded images.
- The final HTML is generated and sent to the browser for printing.
Default Templates
Titan includes three built-in document templates. Download them as a starting point and modify the HTML to create your own custom designs.
| Document | Description | Download |
|---|---|---|
| Treatment Letter | Full treatment summary with tooth diagrams, intraoral photos, IPR values, attachment ranges, and legend icons. Uses all tag types (simple, special, and legend). | Titan Default Template |
| Aligner Label | Compact 3×4 in label for individual aligner bags. Displays lab, doctor, patient name, and aligner details. | Titan Default Template |
| Patient Label | 4×6 in order label shipped with a batch of aligners. Shows doctor address, patient info, upper/lower aligner counts, and attachment templates. | Titan Default Template |
Tags
| Type | Description | Example |
|---|---|---|
| Simple | Plain text that is directly replaced. | [PATIENT_NAME] |
| Special | Take photos of the teeth | [INTRAORAL_FRONTAL_PHOTO] |
| Legend | Are defined within HTML comments and are used for icons or symbols | MISSING_TOOTH |
Simple Tags
These tags are replaced with plain text from the treatment database.
| Tag | Description |
|---|---|
[PATIENT_NAME] |
Full name of the patient. |
[DOCTOR_NAME] |
Name of the treating doctor. |
[LAB_NAME] |
Name of the lab. |
[DATE] |
Creation date of the document (format: yyyy-MM-dd). |
[TOTAL_PAGES] |
Total number of pages in the document. |
[ACTIVE_ALIGNER] |
Ranges of active aligners. |
[OVERCORRECTIONS] |
Ranges of overcorrection aligners. |
[ACTIVE_RETAINERS] |
Ranges of active retainers. |
[ATTACHMENT_LINGUAL] |
List of teeth with lingual attachments. |
[ATTACHMENT_ARCH] |
Ranges of attachment templates provided. |
[TWIN_BLOCKS] |
Aligner range covered by twin block attachments (e.g. 0-20). Empty when the treatment has none. |
[TREATMENT_NOTES] |
Custom notes written by the doctor for the treatment. |
[ADDRESS] |
Lab's address. |
[MAXILLA_RANGE] |
Maxillary arch range. |
[MANDIBLE_RANGE] |
Mandibular arch range. |
[MAX_RANGE_MAXILLA] |
Total number of maxillary aligners. |
[MAX_RANGE_MANDIBLE] |
Total number of mandibular aligners. |
[ALIGNER_DETAILS] |
Additional aligner-specific info. |
[MORE_DETAILS] |
Extra details like split info. |
[MADE_IN] |
Country of manufacture. |
Example
<p>Patient: [PATIENT_NAME]</p>
<p>Doctor: [DOCTOR_NAME]</p>
<p>Date: [DATE]</p>
Output
<p>Patient: John Doe</p>
<p>Doctor: Dr. James Wilson</p>
<p>Date: 2021/12/05</p>
You can wrap simple tags inside any HTML element. The system only replaces the tag text, it does not modify your layout.
Required Rules
- Tags must include square brackets.
- Tag names must match exactly (case-sensitive).
- Tags can be placed inside any HTML element.
- Every occurrence is replaced, including inside
<script>blocks and HTML comments. Do not write a tag name in a script to check whether it was replaced; match the bracketed form instead (for example/^\[.*\]$/).
Special Tags
These tags are used to take photos of the teeth in different views.
| Tag | Description |
|---|---|
[INTRAORAL_FRONTAL_PHOTO] |
Frontal intraoral photo of the patient. |
[INTRAORAL_RIGHT_LATERAL_PHOTO] |
Right lateral intraoral photo. |
[INTRAORAL_LEFT_LATERAL_PHOTO] |
Left lateral intraoral photo. |
[INTRAORAL_UPPER_PHOTO] |
Photo of the upper arch. |
[INTRAORAL_LOWER_PHOTO] |
Photo of the lower arch. |
[INTRAORAL_UPPER_OCCLUSAL_PHOTO] |
Occlusal photo of the upper arch. |
[INTRAORAL_LOWER_OCCLUSAL_PHOTO] |
Occlusal photo of the lower arch. |
[INTRAORAL_OVERJET_VIEW_PHOTO] |
Overjet view photo. |
Required Rules
- Must be inside an element with class
image-placeholder. - Do not wrap the tag inside additional nested elements.
- Do not rename the class
image-placeholder. - Only one special tag per placeholder container.
If these rules are not followed, the image may not render.
Example usage in HTML
<div class="image-container">
<div class="image-placeholder image filled">[INTRAORAL_RIGHT_LATERAL_PHOTO]</div>
</div>
Legend Tags
Legend tags are used for icons and visual tooth indicators. These tags are defined in a special comment block at the end of the template.
Location in HTML
<!--
----------------------------------------------------------------------
Custom Legend Tags:
----------------------------------------------------------------------
<div data-legend-key="MISSING_TOOTH">
<span class="material-icons">close</span>
</div>
<div data-legend-key="EXTRACTION_TOOTH">
<span class="material-icons red">close</span>
</div>
... (more definitions) ...
----------------------------------------------------------------------
End of Custom Legend Tags:
----------------------------------------------------------------------
-->
How it works
- The system scans the HTML for this comment block.
- It extracts each
<div>with the attributedata-legend-key="KEY_NAME". - The inner HTML of that
<div>becomes the replacement template for the legend keyKEY_NAME.
Required Rules
- Must be inside an HTML comment block.
- Must use
data-legend-key="KEY_NAME". - The key must match the query name exactly.
- Do not remove the comment delimiters.
- The legend block must remain at the end of the template.
If the legend block is removed, all conditional icons will fail.
Treatment Letter Processing Rules
Tooth Features
Each tooth in the treatment plan is evaluated for a set of visual features. These features can be either global (apply to the entire tooth) or side-specific (apply only to the buccal or lingual view).
| Feature | Type | Query Key | Description |
|---|---|---|---|
| Missing Tooth | Global | MISSING_TOOTH |
The tooth is not present in the treatment. |
| Extraction Tooth | Global | EXTRACTION_TOOTH |
The tooth is scheduled for extraction. |
| Pontics | Global | PONTICS |
A pontic is present in this position. |
| Tunnel | Side-Specific | TUNNEL |
A tunnel attachment is present on the specified side. |
| Attachments | Side-Specific | ATTACHMENTS |
A standard attachment is present on the specified side. |
| Bite Ramps | Side-Specific | BITE_RAMPS |
A bite ramp is present on the specified side. |
| Cutouts | Side-Specific | CUTOUTS |
Precision cuts are present on the specified side. |
| Elastic Cuts | Side-Specific | ELASTIC_CUTS |
Cuts for elastic hooks are present on the specified side. |
| Power Ridges | Side-Specific | POWER_RIDGES |
Power ridges are present on the specified side. |
| Pressure Points | Side-Specific | PRESSURE_POINTS |
Pressure points are present on the specified side. |
How it works in the HTML
- A tooth element is defined with a
tagattribute (e.g.,tag="TOOTH_UR8"). - Conditional queries are placed inside the element (e.g.,
[ATTACHMENTS?][BITE_RAMPS?]). - The system uses the CSS class of the parent container (
buccal-vieworlingual-view) to determine which side-specific features to evaluate. - If a feature is present, its legend template (from the Custom Legend Tags comment block) is rendered. If not, the query is removed, leaving the element empty (and thus hidden).
Required Structure (Tooth Containers)
<div class="tooth-state buccal-view" tag="TOOTH_UR4" hidden>
[ATTACHMENTS?]
</div>
Required Rules
- Must include tag="TOOTH_XXX".
- Must include either buccal-view or lingual-view for side features.
- Must include hidden attribute initially.
- Tag names must follow exact tooth naming convention.
If a container becomes empty after processing, it will be removed.
[OVERVIEW] Feature
The [OVERVIEW?] query is a special conditional feature used in Treatment Letter templates. It displays a single visual indicator per tooth, automatically selecting the highest-priority feature present for that tooth. This is useful when you want a simplified representation instead of rendering multiple icons.
Instead of writing multiple conditional queries like:
[EXTRACTION_TOOTH?][MISSING_TOOTH?][ATTACHMENTS?][BITE_RAMPS?]
You can simply use:
[OVERVIEW?]
The system will decide which feature to display.
Conditional Query
Conditional queries control whether a feature renders.
Syntax
[FEATURE_KEY + ?]
Example usage in HTML
<div class="tooth-state buccal-view" tag="TOOTH_UR8" hidden>
[ATTACHMENTS?]
</div>
If the feature exists:
-
hiddenis removed -
The legend template is inserted
If not:
- The container is removed
Required Rules
- Must include the question mark ?.
- Must be inside a container with a valid tag attribute.
- Container must start with hidden.
- Must use valid tooth tag format (e.g., TOOTH_UR8).
IPR
IPR information is displayed in the spaces between teeth.
How it works in the HTML
- An IPR space is defined as a
divwithclass="container-ipr"and atagattribute (e.g.,tag="TOOTH_UR5-UR4"). - The container must also have a class of
ipr-above(for upper arch) oripr-below(for lower arch) to control the layout. - The placeholder
[IPR]inside the.grid-areadiv is replaced with the final IPR values and the horizontal lines.
Required Rules
- Must include class
container-ipr. - Must include either
ipr-aboveoripr-below. - Must include valid adjacent tooth tag format.
- Must contain
[IPR]inside.grid-area.
If no IPR exists for that space, the entire container is removed from the final document.
Example usage in HTML
<div class="container-ipr ipr-above" tag="TOOTH_UR5-UR4">
<div class="grid-area">[IPR]</div>
</div>
Aligner Ranges
Aligner ranges show the stages for which a feature (like an attachment) is active on a specific tooth.
Key Rules
- Side-Specific: The range displayed depends on the view (
buccal-vieworlingual-view). The system will show the range for attachments on the relevant side. - Combined Ranges: If a tooth has attachments on both sides, the ranges are combined and displayed in the overview (
[OVERVIEW?]) query.
How it works in the HTML
- An aligner range indicator is a
divwithclass="container-line", atagattribute (e.g.,tag="TOOTH_UR8"), and a view class (e.g.,class="buccal-view"). - The query
[ALIGNER_RANGE?]inside this container is replaced with the text of the range (e.g.,3-14). - If no range exists for that tooth and side, the entire
container-lineblock is removed from the document.
If a range exists:
-
hiddenis removed -
Range text (e.g. 3-14) is inserted
If no range exists:
- The entire container is removed
Example usage in HTML
<div class="container-line buccal-view" tag="TOOTH_UR8" hidden>
<div>[ALIGNER_RANGE?]</div>
</div>
General Customization Guidelines
You may safely:
- Modify CSS
- Change layout
- Resize icons
- Change fonts
- Move containers
- Add page breaks
Do NOT:
- Rename required classes (image-placeholder, container-ipr, container-line)
- Remove the legend comment block
- Remove tag attributes
- Remove hidden from conditional containers
- Change tag keys
If these structural elements are modified or removed, certain features may not render correctly.
Internationalization (Multi-language)
Templates can render their static text in multiple languages. Translation runs in the browser/headless renderer via a small shared script; the template is self-contained (it references the script itself). English is the source language and stays inline in the HTML — you only add translations for the other languages.
Supported language codes: es, pt-BR, fr, ja, ko (English needs no entry).
How it works
- The template's
<head>references the shared translation script. - A JSON block maps each exact English text to its translations.
- Every translatable element is marked with
class="tr"; the script looks up its trimmed text in the JSON and replaces it. - The language is chosen from
data-lang(the app fills the[DOC_LANG]token with the current app language). On older app builds that don't fill the token, the script falls back to the browser language.
The script only translates. Auto-print is handled separately, so you never add print code to the template.
What to add to a template
1. Reference the script in <head>:
<script src="https://server.titandentaldesign.com/cloud/downloads/templates/titan-doc-i18n.js"></script>
(Use the absolute URL — the printed document is opened from a temp file, so relative paths do not work. Mirror the host used by the template images.)
2. Add the translations block (anywhere in the body; keep id, type and the data-lang token exactly):
<script id="titan-translations" type="application/json" data-lang="[DOC_LANG]">
{
"Upper:": { "es": "Superior:", "pt-BR": "Superior:", "fr": "Supérieur :", "ja": "上顎:", "ko": "상악:" },
"Patient Name:": { "es": "Paciente:", "pt-BR": "Paciente:", "fr": "Patient :", "ja": "患者名:", "ko": "환자 이름:" }
}
</script>
3. Mark each static text with class="tr":
<p class="patient-title tr">Orthodontic Aligner Appliances for:</p>
Required rules
- Mark only fully-static text. Data tags (
[PATIENT_NAME], etc.) are replaced before the browser runs, so an element likeof [MAX_RANGE_MAXILLA]would no longer match its key. Wrap just the static word in its own span:
```html
of [MAX_RANGE_MAXILLA]
``
- The JSON key must be the English text **exactly and trimmed**, identical to what the element shows.
- Do **not** put data tags ([...]) inside translation values.
- Do **not** remove or renamedata-lang="[DOC_LANG]", theid="titan-translations", or theclass="tr"` markers.
- If the block or the script is missing, the document still prints — just untranslated (English).
Consistency with the app UI
For clinical/appliance terms, reuse the app's existing translations (I2 term path TreatmentOverview Popup/*) so the printed document matches the on-screen wording — e.g. Attachment → Atache, Power Ridge → Cresta de Poder, Bite Ramp → Rampa Mordida.
Deployment note
titan-doc-i18n.js lives in the shared cloud/downloads/templates/ folder on each server (that is the URL every template points to). The default template HTML files are served per environment (Dev from the shared folder; QA/EA/Live from their versioned folder). These assets are uploaded manually (not by the standard PHP deploy), so a template/JS change must be copied to the server’s downloads/templates locations to take effect. Template files are served without a Cache-Control header, so after updating one, bypass caches when verifying (e.g. append ?v=123).