Literal text

In the process of building an impressive web component, I resorted to JavaScript to mark up ancillary text in a specific structure.

<p><time>March 16 9.27 AM</time> | <span>0 characters</span></p>

Here we have a paragraph housing two additional elements: time to relate a date and span to highlight the number of characters in an element yet to exist. The two are separated with whitespace and a stylish pipe character.

Recreating the structure with JavaScript, while keeping a reference to the different nodes, is far from complicated.

With document.createElement we create three separate nodes, differentiating the three by name.

const details = document.createElement('p');
const time = document.createElement('time');
const characters = document.createElement('span');

From this point we can inject the content. Ideally, and for the time element, we could enhance the structure with more relevant, up-to-date information — perhaps with the current instant —, giving careful consideration for the datetime attribute as well, but let us start by repeating the same exact text as the opening snippet.

Add the text through the textContent property and repeat the effort for the span element detailing the initial number of characters.

time.textContent = 'March 16 9.27 AM';
characters.textContent = '0 characters';

Now, you can add both elements to the parent paragraph with the appendChild method.

details.appendChild(time);
details.appendChild(characters);

With a glaring problem. There is no whitespace, no fancy pipe to separate the content, which is squished up in a cumbersome, slightly hideous design.

Well, I once had the luck to glimpse at the value returned by other JavaScript helper functions, while inspecting the DOM, and seem to remember a mention of a text node. Knowing this, why not just go through the sequence used for the existing nodes?

Create a text element with document.create and add the characters with the textContent property.

const separator = document.createElement('text');
separator.textContent = ' | ';

Append the element, between the previous two and certainly, the result is bound to appear, formatted and clean.

details.appendChild(time);
details.appendChild(separator);
details.appendChild(characters);

Technically, yes, but you should resist the temptation of copying the code.

March 16 9.27 AM | 0 characters <time> <text> <span>

The date and number of characters are indeed separated, but studying the DOM an additional element pops up: text. Unfortunately, and outside of SVG, the HTML reference makes no mention of the tag name. There is no such thing. And even if the result does work, you should not rely on the forgiving nature of modern browsers.

As with custom elements, the node is treated as a generic container. But even as a custom element, there is something inherently wrong, an invalid name. Valid custom elements are defined with at least two words separated with a hyphen, to distinguish your creations from standard nodes.

Back to the pertinent snippet. To resolve the structure at hand, there is a proper way in JavaScript through the Text class. The idea is to create an instance with the new keyword.

const separator = new Text();

On the instance you do have the opportunity to add the text, once again with textContent, but if you enjoy brevity, you also have the option to add the content directly, through the class.

// separator.textContent = " | ";
const separator = new Text(' | ');

This time, you have a reference to proper text, which you can then locate between the two other nodes.

details.appendChild(time);
details.appendChild(separator);
details.appendChild(characters);

And find the desired markup, just waiting to be of more use. A small reminder to give your eyes, and fleeting memories, the weight they deserve.