JSFiddle - React, Tailwind, and code Playground
HTML
<div class="article truncate">
<h3 class="truncate_test_string_shoobodooh">Loremitis!</h3>
<p class="truncate_test_string_shoobodooh">Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Vestibulum laoreet, <b class="truncate_test_string_shoobodooh">nunc eget laoreet sagittis</b>,
quam <em>ligula sodales orci, congue imperdiet</em> eros tortor ac lectus.</p>
<p>Duis <i>eget nisl orci.<br/> Aliquam mattis purus non mauris
blandit id luctus felis convallis.
Integer varius <span>egestas vestibulum</span>.
Nullam a </i>dolor arcu, ac tempor elit. Donec.</p>
</div>
<div class="article truncate_2">
<h3>Loremitis!</h3>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Vestibulum laoreet, <b>nunc eget laoreet sagittis</b>,
quam <em>ligula sodales orci, congue imperdiet</em> eros tortor ac lectus.</p>
<p>Duis <i>eget nisl orci.<br/> Aliquam mattis purus non mauris
blandit id luctus felis convallis.
Integer varius <span>egestas vestibulum</span>.
Nullam a </i>dolor arcu, ac tempor elit. Donec.</p>
</div>
<div class="article truncate_3">
<h3>Loremitis!</h3>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Vestibulum laoreet, <b>nunc eget laoreet sagittis</b>,
quam <em>ligula sodales orci, congue imperdiet</em> eros tortor ac lectus.</p>
<p>Duis <i>eget nisl orci.<br/> Aliquam mattis purus non mauris
blandit id luctus felis convallis.
Integer varius <span>egestas vestibulum</span>.
Nullam a </i>dolor arcu, ac tempor elit. Donec.</p>
</div>
CSS
body {
font-family: Calibri, Arial;
margin: 0px;
padding: 0px;
}
a {
color: #0254EB
}
a:visited {
color: #0254EB
}
.article {
width: 400px;
background-color: #f0f0f0;
margin: 10px;
padding:5px;
}
a.morelink,
a.lesslink {
text-decoration:none;
outline: none;
}
JavaScript
/**
* Script found at http://jsperf.com/html-truncate-by-javascript/3
*/
var Stack = function () {
this.items = [];
};
Stack.prototype = {
size: function () {
return this.items.length;
},
push: function (key) {
this.items.push(key);
},
pop: function () {
return this.items.pop();
},
/**
* dump all close tags and append to truncated content while reaching upperbound
*/
dumpCloseTag: function () {
var html = '',
i, len, tag;
for(i = 0, len = this.size(); i < len; ++i) {
tag = this.pop();
html += '</' + tag.tag + '>';
}
return html;
}
};
var stack = new Stack();
/**
* HTML-Truncate Utility
* This utility truncates html text and keep tag safe(close properly)
*/
function truncate(str, maxLength) {
var content = '', // traced text
total = 0, // record how many characters we traced so far
matches = true,
result, index, tag, tail;
while(matches) {
// find tags
matches = /<\/?\w+(\s+\w+="[^"]*")*>/g.exec(str);
if(!matches) break;
var result = matches[0],
index = matches.index;
// overceed, dump everything to clear stack
if (total + index > maxLength) {
content += str.substring(0, maxLength - total);
content += stack.dumpCloseTag();
break;
} else {
total += index;
content += str.substring(0, index);
}
if (-1 === result.indexOf('</')) {
tail = result.indexOf(' ');
tail = (-1 === tail) ? result.indexOf('>') : tail;
stack.push({
tag: result.substring(1, tail),
html: result
});
} else {
stack.pop();
}
content += result;
str = str.substring(index + result.length);
}
return content;
}
/**
* end script
*/
/**
...