Handlebars {{#if}} Treats Empty Arrays as Truthy: Diagnostic Guide
Handlebars {{#if}} treats empty arrays and objects as truthy, so empty collections can render content you expected to hide. Use .length or a custom helper to test collections reliably.
14 Jul 2025, 10:35 UTC

The problem: an empty array still renders the main branch
In Handlebars.js 4.x, {{#if items}} renders its main block when items is an empty array [] or an empty object {}. Many developers expect empty collections to behave like falsy values and skip the block. The template can render content you intended to hide, producing stray UI elements, empty list wrappers, or confusing "no results" messages.
Useful takeaway: {{#if}} follows JavaScript truthiness for single values such as strings, numbers, and booleans, but it does not treat empty arrays or objects as falsy. Test collections with .length or a custom helper, and remember that 0 and "" are falsy even when they are valid IDs or codes.
Cause and diagnostic table
| Value passed to {{#if}} | Handlebars 4.x result | Common incorrect assumption | Typical symptom |
|---|---|---|---|
false, undefined, null | Falsy; renders the {{else}} block | None | Expected fallback appears |
"", 0, NaN | Falsy; renders the {{else}} block | A valid zero ID or empty code should show content | Content disappears for zero or empty string |
[], {} | Truthy; renders the main block | An empty collection should skip the block | Empty list wrapper or table renders |
| Non-empty string, number, or object | Truthy; renders the main block | None | Expected content appears |
Ordered checks
- Identify the template block and the value it inspects.
- Check the data type of that value in the rendering context.
- Determine whether the value is a scalar, an array, or an object.
- Reproduce with a minimal template and inspect which branch renders.
- Decide whether the fix is a length check, a custom helper, or a data normalization change.
Fixes tied to findings
Empty array or object
If the value is an array, check its length instead of the reference:
{{#if items.length}}
{{#each items}}- {{this}}
{{/each}}
{{else}}
No items found.
{{/if}}
Handlebars has no built-in isEmpty helper. For objects, register a helper in the Node.js process where your Handlebars instance is configured:
Handlebars.registerHelper('isEmpty', function(value) {
if (value === null || value === undefined) return true;
if (Array.isArray(value)) return value.length === 0;
if (typeof value === 'object') return Object.keys(value).length === 0;
return false;
});
Then use {{#if (isEmpty items)}} in the template. Helper return values are subject to the same truthiness rules, so returning 0 from a helper in {{#if}} is falsy.
Zero or empty string is a valid value
Because 0 and "" are falsy, a numeric ID or code can hide content unexpectedly. Compare explicitly with a helper:
{{#if (hasValue orderId)}}
Order {{orderId}}
{{else}}
No order selected.
{{/if}}
Implement hasValue to return true for 0 and "" while remaining false for null, undefined, and missing values.
Using {{#unless}}
{{#unless}} inverts the same truthiness rules. {{#unless items}} renders when items is falsy, but because [] is truthy, the block will not render for an empty array. Apply the same length or helper checks shown above.
Concrete verification example
Create a Node.js script file, for example check-truthiness.js, and run it with Node. No special permissions are required. Replace VALUE_PLACEHOLDER with the value you want to inspect.
const Handlebars = require('handlebars');
console.log('Handlebars version:', Handlebars.version);
const template = Handlebars.compile('{{#if value}}TRUTHY{{else}}FALSY{{/if}}');
const cases = [
{ label: 'empty array', value: [] },
{ label: 'empty object', value: {} },
{ label: 'undefined', value: undefined },
{ label: 'zero', value: 0 },
{ label: 'empty string', value: '' },
{ label: 'false', value: false }
];
for (const c of cases) {
const result = template({ value: c.value });
// Inspect result to confirm whether TRUTHY or FALSY appears.
console.log(c.label, '=>', result);
}
Expected checks: confirm that [] and {} produce TRUTHY, while undefined, null, 0, "", and false produce FALSY. Do not assume the output without running the script against your installed Handlebars version.
Risk: leaving diagnostic scripts in a repository can expose template internals. Remove or isolate them after verification.
Limitations
- This behavior applies to Handlebars 4.x. Other major versions may differ.
{{#if}}does not support strict equality (===) directly in the block expression.- HTML escaping inside an
{{#if}}block is unchanged; truthiness only controls which branch renders. - Custom helpers add runtime overhead and must be registered before template compilation if referenced in precompiled templates.
Practical way to check the result
Write a unit test that renders {{#if items}}yes{{else}}no{{/if}} with items: [] and asserts that the output contains yes. Then render the same template with items: undefined and assert that the output contains no. If your application relies on empty collections skipping a block, update the template to use {{#if items.length}} or the custom helper and re-run the test.
Escalation criteria
Escalate to the template or data-layer maintainer when:
- The same value renders differently across server-side and client-side Handlebars instances, suggesting a version mismatch.
- A custom helper is required in dozens of templates, indicating the data should be normalized before it reaches the view.
- Precompiled templates fail after adding a helper because the helper was not available at compile time.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.