Many tools give special treatment to literals tagged by a particular name.
const doc = html`<!DOCTYPE html>
<html lang="en-US">
<head>
<title>Hello</title>
</head>
<body>
<h1>Hello world!</h1>
</body>
</html>
`;
One might naïvely implement the html tag as:
This, in fact, works for the case above. However, because String.raw would concatenate the raw string literals instead of the "cooked" ones, escape sequences would not be processed.
const doc = html`<canvas>\n</canvas>`;
This may not be what you want for a "true identity" tag, where the tag is purely for markup and doesn't change the literal's value. In this case, you can create a custom tag and pass the "cooked" (i.e. escape sequences are processed) literal array to String.raw, pretending they are raw strings.
const html = (strings, ...values) => String.raw({ raw: strings }, ...values);
const doc = html`<canvas>\n</canvas>`;
Notice the first argument is an object with a raw property, whose value is an array-like object (with a length property and integer indexes) representing the separated strings in the template literal. The rest of the arguments are the substitutions. Since the raw value can be any array-like object, it can even be a string! For example, 'test' is treated as ['t', 'e', 's', 't']. The following is equivalent to `t${0}e${1}s${2}t`:
String.raw({ raw: "test" }, 0, 1, 2);