Customise the appearance of printed and previewed documents by writing your own HTML templates using the Liquid templating language. When a template is assigned to a transaction, Basis renders it in a browser-native preview instead of the built-in QuestPDF layout — giving you full control over fonts, colours, and structure.
| Concept | Description |
|---|---|
| Template | An HTML + Liquid file you write and save under Settings |
| Assignment | Each transaction can optionally reference one template |
| Fallback | If no template is assigned, the built-in PDF is used as usual |
The editor accepts standard HTML, CSS, and Liquid
{{ }}/{% %}tags. No external dependencies are required — system fonts are used by default.
On any Create or Edit form (Sales Invoice, Purchase Invoice, Payment, Receipt, Journal Entry, etc.), find the Print Template field. Select your template from the dropdown or leave it as Built-in to use the default PDF.
The selected template is saved with the transaction and used every time that document is previewed or printed.
Open any transaction and click Preview. If a template is assigned:
@media print { } rules in your template control how the printed page looks.If no template is assigned, the built-in QuestPDF viewer is shown instead.
All variables are accessed with {{ variable }} syntax.
| Variable | Description |
|---|---|
business.name |
Company name |
business.address |
Full formatted address |
business.logo_url |
Logo as base64 data URL |
business.phone |
Phone number |
business.email |
Email address |
business.tax_number |
Tax registration number |
| Variable | Description |
|---|---|
document.type |
Built-in document type name (e.g. "Sales Invoice") |
document.custom_title |
User-set custom title for this document, if any (otherwise empty) |
document.title |
Effective title — the custom title if set, otherwise document.type. Use this for the printed heading. |
document.number |
Document number (e.g. "SI-2024-0001") |
document.date |
Date, formatted (e.g. "01/06/2026") |
document.date_long |
Date in long format (e.g. "1 June 2026") |
document.due_date |
Due date, formatted |
document.due_date_long |
Due date in long format |
document.reference_number |
Reference / supplier invoice number |
document.narration |
Notes / description |
document.currency |
Currency code (e.g. "IDR") |
document.salesman |
Salesman name (if applicable) |
document.project |
Project name (if applicable) |
document.amount_in_words |
Grand total in words (e.g. "One Million Rupiah") |
| Variable | Description |
|---|---|
document.subtotal |
Total before tax and discount |
document.total_discount |
Total discount amount |
document.total_tax |
Total tax amount |
document.total_wht |
Total withholding tax |
document.grand_total |
Final payable amount |
| Variable | Description |
|---|---|
document.party.name |
Party name |
document.party.address |
Full formatted address |
document.party.tax_number |
Party tax number |
document.party.phone |
Party phone number |
Iterate with {% for item in document.items %} ... {% endfor %}.
| Variable | Description |
|---|---|
item.line_number |
Line number (1-based) |
item.item_code |
Item code |
item.item_name |
Item name |
item.item_description |
Optional description |
item.quantity |
Quantity |
item.unit |
Unit of measure |
item.unit_price |
Price per unit |
item.discount_percent |
Discount percentage |
item.discount_amount |
Flat discount amount |
item.line_subtotal |
Line amount before tax |
item.tax_name |
Tax category name |
item.tax_rate |
Tax rate (%) |
item.tax_amount |
Tax amount for this line |
item.amount |
Line total (after tax) |
Use {{ labels.* }} to output text that automatically adapts to the active app language (English or Indonesian).
| Variable | English | Indonesian |
|---|---|---|
labels.bill_to |
BILL TO | TAGIHAN KEPADA |
labels.date |
Date | Tanggal |
labels.due_date |
Due Date | Jatuh Tempo |
labels.reference |
Reference | Referensi |
labels.salesman |
Salesman | Salesman |
labels.no |
No. | No. |
labels.description |
Description | Keterangan |
labels.qty |
Qty | Jumlah |
labels.unit_price |
Unit Price | Harga Satuan |
labels.line_amount |
Amount | Jumlah |
labels.tax |
Tax | Pajak |
labels.total |
Total | Total |
labels.subtotal |
Subtotal | Subtotal |
labels.total_discount |
Discount | Diskon |
labels.total_tax |
Tax | Pajak |
labels.grand_total |
Grand Total | Grand Total |
labels.amount_in_words |
Amount in Words | Terbilang |
labels.notes |
Notes / Terms | Catatan / Syarat |
labels.received_by |
Received by | Diakui Pelanggan |
labels.approved_by |
Approved by | Disetujui oleh |
labels.prepared_by |
Prepared by | Dibuat oleh |
labels.page |
Page | Halaman |
| Filter | Example | Output |
|---|---|---|
money |
{{ 1500000 \| money }} |
1,500,000.00 (EN) / 1.500.000,00 (ID) |
date |
{{ document.date \| date: "dd/MM/yyyy" }} |
01/06/2026 |
upcase |
{{ document.type \| upcase }} |
SALES INVOICE |
downcase |
{{ "Hello" \| downcase }} |
hello |
Tip: Use
{{ document.date_long }}and{{ document.due_date_long }}directly — they are already formatted for the active language without needing a filter.
{% if business.logo_url %}
<img src="{{ business.logo_url }}" alt="Logo">
{% else %}
<strong>{{ business.name }}</strong>
{% endif %}
{% if document.total_discount > 0 %}
<tr><td>Discount</td><td>{{ document.total_discount | money }}</td></tr>
{% endif %}
@page { size: A4 portrait; margin: 10mm 12mm; } in your CSS. Without it the browser uses its own default paper size and the PDF may not be A4.@page margin rule controls print margins. Use @media screen { body { padding: 12mm; } } for the on-screen preview and @media print { body { padding: 0; } } to let @page handle margins.'Segoe UI', system-ui, -apple-system, Arial, sans-serif — no external font imports needed.