Using variables

Declare and update variables inside a template with #{ … }#, and carry a running total across a loop.

A statement block runs code without writing anything to the output. That is what lets a template accumulate a subtotal while it renders the rows, then use it in the summary lines underneath.

<style>
    body { font: 14px/1.5 system-ui, sans-serif; margin: 0; color: #24292f; }
    table { border-collapse: collapse; width: 100%; max-width: 30em; }
    th, td { padding: 5px 8px; text-align: left; }
    th { font-weight: 600; border-bottom: 2px solid #d8dee4; }
    td.num { text-align: right; font-variant-numeric: tabular-nums; }
    tr.sum td { border-top: 1px solid #d8dee4; }
    tr.total td { border-top: 2px solid #24292f; font-weight: 700; }
    .label { color: #57606a; }
</style>

<script type="text/template" id="invoice">
    #{ let subtotal = 0; }#
    <table>
        <thead>
            <tr><th>No.</th><th>Item</th><th class="num">Qty</th><th class="num">Unit</th><th class="num">Line</th></tr>
        </thead>
        <tbody>
        #for(let i = 0; i < lines.length; i++) {#
            #{ let line = lines[i]; let amount = line.qty * line.unit; subtotal += amount; }#
            <tr>
                <td class="label">#i + 1#</td>
                <td>#line.name#</td>
                <td class="num">#line.qty#</td>
                <td class="num">#line.unit#</td>
                <td class="num">#amount#</td>
            </tr>
        #}#
            #{ let vat = Math.round(subtotal * vatRate); }#
            <tr class="sum"><td colspan="4" class="label">Subtotal</td><td class="num">#subtotal#</td></tr>
            <tr><td colspan="4" class="label">VAT #vatRate * 100#%</td><td class="num">#vat#</td></tr>
            <tr class="total"><td colspan="4">Total</td><td class="num">#subtotal + vat#</td></tr>
        </tbody>
    </table>
</script>

<div id="output"></div>

<script src="https://cdn.jsdelivr.net/gh/richdafunk/hashJS@v1.3.6/hashJS.js"></script>
<script>
    const data = {
        vatRate: 0.25,
        lines: [
            { name: 'Design retainer',   qty: 1,  unit: 18000 },
            { name: 'Development hours', qty: 42, unit: 1150 },
            { name: 'Hosting, 12 months', qty: 12, unit: 490 }
        ]
    };

    new hashJS('invoice', data, 'output');
</script>
Output result:

The distinction is between the two forms. #…# evaluates an expression and appends the result; #{ … }# runs statements and appends nothing. Everything else follows from normal JavaScript scoping: subtotal is declared before the loop and survives it, while amount is declared inside the loop body and is fresh on every row.

This example also uses a counting for loop rather than for…of, so the row number is available as #i + 1#. Both compile to the loop you wrote; neither is a special case.

Because the total is computed during rendering rather than prepared beforehand, the template stays correct when the caller adds a line — there is no second place to update.