Using Tagged Template Literals to escape embedded HTML
JavaScript template strings are great for building HTML templates.
But there’s a problem: embedding a template string into your page can be a security risk
// This is risky
element.innerHTML = `<div id="page">${userDefinedContent}</div>`;
But there’s a super-convenient feature of template strings called “Tagged Template Literals.” It looks like this:
// We're appending our template string onto something called safeHTML...
element.innerHTML = safeHTML`<div id="page">${userDefinedContent}</div>`;
To be clear, safeHTML
isn’t a language feature. It’s just an arbitrary function name. So the code above is functionally the same as this:
// Pass our template through safeHTML before assigning it to innerHTML
element.innerHTML = safeHTML(templateData, userDefinedContent);
So if we have a function named safeHTML
, we can use it to escape the user content before embedding it. There are a couple ways we could do this:
- Option 1: Define the
safeHTML
escaping function ourselves. There are examples online we can use to help us (like this one). - Option 2: Pull in a 3rd-party function that does the escaping for us.
For option 2, I found a small library called html-template-tag which you can use like this:
import html from 'html-template-tag';
// Now, userDefinedContent will be escaped, without affecting our wrapper div.
element.innerHTML = html`<div id="page">${userDefinedContent}</div>`;
This escaping function is great if you don’t want any user-defined HTML in your page.
Sometimes you do want user-defined HTML though, like basic text formatting, for example. In that case, you’d need a different function that allows some HTML tags to remain unescaped. Different use-cases will require some combination or escaping, filtering, validating, or sanitizing. Fortunately, there are tons of tagged-template modules out there that can help with these scenarios.
You can do lots of other things with tagged template literals, with libraries doing everything from stripping indentation to building a Virtual DOM. Hopefully this is a nice introduction to the options that are out there.