Does JavaScript have a way of truncating HTML text without all the headaches of matching tags etc etc?
Thank you.
Does JavaScript have a way of truncating HTML text without all the headaches of matching tags etc etc?
Thank you.
I know this question is old, but I recently had the same problem. I wrote the following library, which truncates valid HTML safely: https://github.com/arendjr/text-clipper
If you want a light-weight solution in vanilla JS, this should do the trick, although it'll leave empty elements around, so it depends on if you care about those. Also note that it mutates the nodes in-place.
function truncateNode(node, limit) {
if (node.nodeType === Node.TEXT_NODE) {
node.textContent = node.textContent.substring(0, limit);
return limit - node.textContent.length;
}
node.childNodes.forEach((child) => {
limit = truncateNode(child, limit);
});
return limit;
}
const span = document.createElement('span');
span.innerHTML = '<b>foo</b><i>bar</i><u>baz</u>';
truncateNode(span, 5);
expect(span.outerHTML).toEqual('<span><b>foo</b><i>ba</i><u></u></span>');
None of the above solutions corresponded perfectly to my use case, so I created myself a small vanilla javascript function. It leaves empty elements but it could be corrected easily.
const truncateWithHTML = (string, length) => {
// string = "<span class='className'>My long string that</span> I want shorter<span> but just a little bit</span>"
const noHTML = string.replace(/<[^>]*>/g, '');
// if the string does not need to be truncated
if (noHTML.length <= max){
return string;
}
// if the string does not contains tags
if (noHTML.length === string.length){
// add <span title=""> to allow complete string to appear on hover
return `<span title="${string}">${string.substring(0, max).trim()}…</span>`;
}
const substrings = string.split(/(<[^>]*>)/g).filter(Boolean);
// substrings = ["<span class='className'>","My long string that","</span>"," I want shorter","<span>"," but just a little bit","</span>"]
let count = 0;
let truncated = [];
for (let i = 0; i < substrings.length; i++) {
let substr = substrings[i];
// if the substring isn't an HTML tag
if (! substr.startsWith("<")){
if (count > length){
continue;
} else if (substr.length > (length-count-1)){
truncated.push(substr.substring(0, (length-count) - 1) + '…');
} else {
truncated.push(substr);
}
count += substr.length;
} else {
truncated.push(substr);
}
}
return `<span title="${noHTML}">${truncated.join("")}…</span>`;
}
Examples:
string = "<span class='className'>My long string that</span> I want shorter<span> but just a little bit</span>";
truncateWithHTML(string,10); // "<span title='My long string that I want shorter but just a little bit'><span class='className'>My long s…</span><span></span></span>"
truncateWithHTML(string,22); // "<span title='My long string that I want shorter but just a little bit'><span class='className'>My long string that</span> I…<span></span></span>"