Safely Escaping HTML with a Custom Handlebars Helper in Node.js
Create a Handlebars helper that safely escapes HTML in Node.js, register it, test it, and troubleshoot common pitfalls—no raw tags, no triple braces, just clean output.
09 Jul 2026, 19:32 UTC

Desired Outcome
Implement a Handlebars helper named escapeHtml that returns a string with all HTML special characters converted to their entity equivalents. The helper should be usable in templates via {{escapeHtml value}} and must never render raw HTML, even if the input contains tags or scripts.
Prerequisites
- Node.js v18 or newer (recommended 20.x for LTS support)
- npm or yarn package manager
- Handlebars 4.x installed in the project:
npm install handlebars - Basic understanding of module exports and how Handlebars registers helpers
Step‑by‑Step Procedure
- Create a helpers folder
mkdir -p src/helpers - Define the helper
// src/helpers/escapeHtml.js const Handlebars = require('handlebars'); /** * Escapes HTML special characters in a string. * @param {string|number|null|undefined} value - Input to escape. * @returns {string} Escaped string. */ function escapeHtml(value) { // Handlebars.Utils.escapeExpression handles undefined, null, and numbers. return Handlebars.Utils.escapeExpression(value); } module.exports = escapeHtml; - Register the helper in the application bootstrap
// src/index.js (or wherever you configure Handlebars) const Handlebars = require('handlebars'); const escapeHtml = require('./helpers/escapeHtml'); // The registerHelper call must happen before any template compilation. Handlebars.registerHelper('escapeHtml', escapeHtml); - Use the helper in a template
{{escapeHtml userInput}}Note: use double braces (
{{}}). Triple braces ({{{}}}) bypass escaping and should never be used with this helper.
Verification
After registering, run a quick test to confirm behavior:
const Handlebars = require('handlebars');
const template = Handlebars.compile('{{escapeHtml rawInput}}');
const output = template({ rawInput: '' });
console.log(output); // Expected: <script>alert(1)</script>
Expected output contains <script>alert(1)</script> – no raw tags. If the output still contains < or > characters, the helper is not applied correctly.
Recovery and Troubleshooting
- Helper not applied: Verify that
registerHelperis executed before any template compilation. If templates are compiled at import time, move the registration to the very top of the bootstrap file. - Escaped output missing: Ensure the template uses double braces. Triple braces will output raw content regardless of the helper.
- Undefined or null input: Handlebars will return an empty string. If you need to surface a warning, modify the helper to throw or log when encountering null/undefined.
- Upgrading Handlebars to 5.x: The
Utils.escapeExpressionAPI remains stable, but confirm by running the verification script. If the API changes, adjust the import accordingly.
Optional Unit Test with Jest
Adding a test ensures future changes do not break escaping logic.
// tests/escapeHtml.test.js
const Handlebars = require('handlebars');
const escapeHtml = require('../src/helpers/escapeHtml');
Handlebars.registerHelper('escapeHtml', escapeHtml);
test('escapes script tags', () => {
const template = Handlebars.compile('{{escapeHtml input}}');
const output = template({ input: '' });
expect(output).toBe('<script>alert(1)</script>');
});
Best Practices
- Never expose raw user input via triple braces unless you intentionally want to render HTML.
- Keep helpers stateless; they should only transform data, not alter global state.
- Document the helper’s purpose and usage in README or inline comments to aid future maintainers.
- Consider adding a lint rule that flags the use of triple braces with this helper.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.