# Hypertext Literal
Hypertext Literal is a tagged template literal for HTML which interpolates values *based on context*, allowing automatic escaping and the interpolation of non-serializable values, such as event listeners, style objects, and other DOM nodes. It is inspired by [lit-html](https://lit-html.polymer-project.org/) and [HTM](https://github.com/developit/htm), and references the fantastically precise [HTML5 spec](https://html.spec.whatwg.org/multipage/parsing.html#tokenization).
Hypertext Literal is open-sourced under the permissive ISC license, is small, has no dependencies, and is available [on npm](https://www.npmjs.com/package/htl). To install:
```
npm install htl
```
See this README with live examples on Observable:
https://observablehq.com/@observablehq/htl
## Why not concatenate?
Surely the simplest way to generate web content is to write [HTML](https://developer.mozilla.org/en-US/docs/Web/HTML). Modern JavaScript makes it easier than ever to interpolate values into literal HTML thanks to [template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals).
```js
const value1 = "world";
const html = `
Hello ${value1}
`;
```
Yet simple concatenation has two significant drawbacks.
First, it confounds markup with text and other content. If an interpolated value happens to include characters that are meaningful markup, the result may render unexpectedly. An ampersand (&) can be interpreted as a character entity reference, for instance.
```js
const value2 = "dollars£s";
const html = `My favorite currencies are ${value2}.`;
```
This can be fixed by escaping (say replacing ampersands with the corresponding entity, `&`). But you must remember to escape every time you interpolate, which is tedious! And it’s easy to forget when many values work as intended without it.
```js
const html = `My favorite currencies are ${value2.replace(/&/g, "&")}.`;
```
Second, concatenation impedes composition: interpolated content must be serialized as markup. You cannot combine literal HTML with content created by the DOM API, or a library such as React or D3. And some content, such as event listeners implemented as closures, can’t be serialized!
## Features
Hypertext Literal is a tagged template literal that renders the specified markup as an element, text node, or null as appropriate.
```js
html`I’m an element!` // returns an element
```
```js
html`I’m simply text.` // returns a text node
```
```js
html`` // returns null
```
If multiple top-level nodes are given, the nodes are implicitly wrapped in a SPAN element.
```js
html`I’m an implicit span.` // returns a element
```
If you’d prefer a [document fragment](https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment) instead, as when composing hypertext literal fragments, call html.fragment.
```js
html.fragment`I’m a document fragment.` // returns a DocumentFragment
```
### Automatic escaping
If a value is interpolated into an attribute value or data, it is escaped appropriately so as to not change the structure of the surrounding markup.
```js
html`Look, Ma, ${"automatic escaping"}!`
```
```js
html`This text has color.`
```
In cases where it is not possible to interpolate safely, namely with script and style elements where the interpolated value contains the corresponding end tag, an error is thrown.
```js
html`"}` // Error: cannot interpolate into "}` // Error: cannot interpolate into