If statements

Choose between two pieces of markup with #if(…) {# and #} else {#.

The condition is an ordinary JavaScript expression and the branches are ordinary markup. A record with a title renders one way, a record without renders a placeholder — which is the everyday reason to branch inside a template.

<style>
    body { font: 14px/1.6 system-ui, sans-serif; margin: 0; color: #24292f; }
    ul { list-style: none; padding: 0; margin: 0; }
    li { padding: 8px 0; border-bottom: 1px solid #eaeef2; display: flex; gap: 10px; align-items: baseline; }
    li:last-child { border-bottom: 0; }
    .name { font-weight: 600; min-width: 9em; }
    .muted { color: #8c959f; font-style: italic; }
</style>

<script type="text/template" id="team">
    <ul>
    #for(let m of members) {#
        <li>
            <span class="name">#m.name#</span>
            #if(m.title) {#
                <span class="title">#m.title#</span>
            #} else {#
                <span class="title muted">No title on file</span>
            #}#
        </li>
    #}#
    </ul>
</script>

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

<script src="https://cdn.jsdelivr.net/gh/richdafunk/hashJS@v1.3.6/hashJS.js"></script>
<script>
    const data = {
        members: [
            { name: 'Ada Lovelace',   title: 'Principal engineer' },
            { name: 'Grace Hopper',   title: 'Compiler lead' },
            { name: 'Karen Sparck',   title: '' },
            { name: 'Alan Turing',    title: 'Research' }
        ]
    };

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

Note how the middle of the chain is written: #} else {# is a single tag, not #}# followed by #else {#. Anything ending in { is treated as a block opener and anything beginning with } as a continuation of the block before it. The library never learns the keywords, which is why arbitrary control flow works — try/catch and labelled blocks follow the same rule without anyone adding support for them.

The condition is truthiness, not a comparison: an empty string is falsy, so #if(m.title) covers both a missing property and a blank one.