With tongue firmly in cheek, I created this script to take a chunk of text and break it up into a tweetstorm, for “readability”. Sort of like the opposite of something like Mercury Reader. If the irony is lost on you, it’s a gentle ribbing of people who chose Twitter to publish long-form content, instead of, you know, readable paragraphs.
See the Pen Turning Text into a Tweetstorm by Chris Coyier (@chriscoyier) on CodePen.
It might be fun to look at how it works.
First, we need to bust up the text into an array of sentences.
We aren’t going to do any fancy analysis of where the text is on the page, although is presumably some algorithmic way to do that. Let’s just say we have:
<main id="text">
Many sentences in here. So many sentences. Probably dozens of them.
</main>
Let’s get our hands on that text, minus any HTML, like this:
let content = document.querySelector("#text").textContent;
Now we need to break that up into sentences. That could be as simple as splitting on periods, like content.split(". ")
, but that doesn’t use any intelligence at all. For example, a sentence like “Where are you going, Mr. Anderson?” would be broken at the end of “Mr.” and not at the “?”, which ain’t great.
This is find something on Stack Overflow territory!
This answer is pretty good. We’ll do:
let contentArray = content.replace(/([.?!])\s*(?=[A-Z])/g, "$1|").split("|");
I didn’t bother to try and really dig into how it works, but at a glance, it looks like it deals with a few common sentence-ending punctuation types, and also those “Mr. Anderson” situations somehow.
We need some tweet templates.
There are two: the top one that kicks off the thread and reply tweets. We should literally make a template, because we’ll need to loop over that reply tweet as many times as needed and that seems like way to go.
I reached for Handlebars, honestly because it’s the first one I thought of. I probably could have gone for the ever-simpler Mustache, but whatever it’s just a demo. I also couldda/shouldda gone with a template via Template Literals.
To make the template, the first thing I did was create a tweet with mock data in just HTML and CSS, like I was just devving out a component from scratch.
<div class="tweet">
<div class="user">
<img src="/fake-user.svg" alt="" class="user-avatar">
<div class="user-fullname">Jimmy Fiddlecakes</div>
<div class="user-username">@everythingmatters</div>
</div>
<div class="tweet-text">
Blah blah blah important words. 1/80
</div>
<time class="tweet-time">
5:48 PM - 15 Sep 2017
</time>
yadda yadda yadda
I wrote my own HTML and CSS, but used DevTools to poke at the real Twitter design and stole hex codes and font sizes and stuff as much as I could so it looked real.
To make those tweet chunks of HTML into actual templates, I wrapped them up in script tags how Handlebars does it:
Now I can:
// Turn the template into a function I can call to compile it:
let mainTweetSource = document.querySelector("#main-tweet-template").innerText;
let mainTweetTemplate = Handlebars.compile(mainTweetSource);
// Compile it whenever:
let mainTweetHtml = mainTweetTemplate(data);
The data
there is the useful bit. Kind of the whole point of templates.
What is “data” in a template like this? Here’s stuff:

Which we can represent in an object, just like Handlebars wants:
let mainTweetData = {
"avatar": "200/[email protected]",
"user-fullname": "Jimmy Fiddlecakes",
"user-username": "@everythingmatters",
"tweet-text": "", // from our array!
"tweet-time": "5:48 PM - 15 Sep 2017",
"comments": contentArray.length + 1,
"retweets": Math.floor(Math.random() * 100),
"loves": Math.floor(Math.random() * 200),
"tweet-number": 1,
"tweet-total": contentArray.length
};
Now we loop over our sentences and stitch together the templates.
// .shift() off the first sentence and compile the main tweet template first
let mainTweetHtml = mainTweetTemplate(mainTweetData);
let allSubtweetsHTML = "";
// Loop over the rest of the sentences
contentArray.forEach(function(sentence, i) {
let subtweet_data = {
// gather up the data fresh each time, randomzing numbers and
// most importantly plopping in the new sentence:
"tweet-text": sentence,
...
};
let subTweetHtml = subTweetTemplate(subtweetData);
allSubtweetsHTML += subTweetHtml;
}
// Now dump out all this HTML somewhere onto the page:
document.querySelector("#content").innerHTML = `
<div class="all-tweets-container">
${mainTweetHtml}
${allSubtweets}
</div>
`;
That should do it!
I’m sure there are lots of ways to improve this, so feel free to fork the Pen and have at it. Ultimate points would be to make it a browser extension.
I’d much rather speed read: https://codepen.io/fauxserious/pen/EgWQNq
Hi there,
Just a small question, why in the timeline we have to always render the username?
The RegEx split is over complicating this and misses an important piece. All tweets are 140 (or 280 now) characters or less. So instead just get the length of the string, divide it by 140 or 280, and slice it that many times over. If you want it to be favor, add in some check about spaces and words, but still, no crazy RegEx needed
Even better! That way the tweets don’t end at complete sentences and are even harder to read! ;)
You could combine the approaches to get complete sentences but you can’t guarantee that a complete sentence will always be within a tweet’s length. Most tweets in a tweetstorm aren’t split by sentence anyway, they are typically split after the last possible word.
So really you’d want to slice it, and move the characters from the last space to the start of the next tweet.
Obviously, the JS tips are the real purpose for this post, but for those just looking for a quick way to do this, I just came across Chirr App which is an online tool that does this pretty nicely, with the option to use an ellipsis (…) to indicate that you want the sentences manually divided.
The regex that you used actually doesn’t solve the “Mr. Anderson” case either. Basically, it assumes any capital letter following punctuation is a new sentance, which “Mr. Anderson” fits this criteria, but is clearly not two sentances. Try it for yourself, paste this in your browser’s console, and you’ll end up with 3 tweet blocks, not 2.
I was going to post the same thing. In fact, there’s no easy way to handle the “Mr. Anderson” situation without creating an exhaustive list of abbreviations (“Mr.”, “Mrs.”, “Dr.”, “Ms.”, “St.”, etc.) to exclude from the splitting algorithm.
Also, as other commenters have noted, it’s possible that a single sentence could exceed Twitter’s 140 (or 280) character limit. As a quick proof of concept, the approach presented here is OK, but it’s definitely not production-ready.