Using JavaScript to Avoid Orphans

Image by Alice Donovan Rouse.

In typography, orphans are often confused with widows, which I cover in Using CSS to Deal with Widows, and occasionally also referred to as 'runts'. However you choose to refer to them, these are those annoying singleword lines that hang alone at the end of a block of text or paragraph:

An excerpt from the letter written by Doc to Marty in Back to the Future II explaining the fate of the DeLorean after he (and it) travelled back to 1885. This type set demonstrates an orphan (or 'runt') word in the final line - highlighted in red.

I say these are annoying, but really any frontend developer who has spent a lot of time with hyperfocused designers knows that the real annoyance comes from watching them laboriously pull their browser window in and out, waiting for that one word to drop onto the next line...

The truth is that whilst in typography and print settings these are a genuine concern that is easily resolved by shortening the previous line, in web development it is extremely difficult to naturally balance text across a fluid screen width and multiple breakpoints without an errant orphan popping up at some point. On some screen width. Somewhere.

There is no simple CSSbased solution and in the past, I have seen it spiral into a significant distraction away from more key components within the project, and all for very little return for the enduser. So: to start with, please do consider whether you really do need to tackle this at all. I would argue that the solution to this type of problem is often a compromise somewhere between design, and content; perhaps with a little input from development.

With all that said, there are some occasions where it does make sense to tackle these and pages can look significantly more accomplished with orphans tendedto. For example in the titles of gridbased listing pages such as Blogs or Product Listings:

Screenshot from a Selfridges.com Product Listing Page demonstrating word wrapping to avoid orphaned words in the product titles.

If you are already resigned to using JavaScript for your front end (which you inevitably are if you are using React), and especially if you're also using serverside rendering, then there is a relatively straightforward solution using JavaScript to join the final two words with a nonbreaking space instead of the old <nobr>.

I've written a little utility function which I can drop in wherever the need arises. You can see it in action in my blog article page titles (above), and on the blog listing pages to help improve the way the text falls on the page:

export default (value) => {  if (typeof value !== 'string' || value.trim() === '') {    return value;  }  const words = value.trim().split(/\s+/);  if (words.length < 4) {    return value;  }  const leadingWords = words.slice(0, -2).join(' ');  const finalWords = words.slice(-2).join('\u00a0');  // React renders this return value as text rather than parsing it as HTML.  return `${leadingWords} ${finalWords}`;};

All this does is take the last two words of a string and join them with a non-breaking space. React renders the returned string as text, so untrusted characters are not parsed as HTML. The browser will pull the preceding word down with the final word rather than leaving it alone.

A nonbreaking space is ordinary text rather than an HTML injection sink. The old nobr (the 'nonbreaking text element') was never a standard HTML feature. Although it is widely supported across different browsers, it is not used by the corrected example. The two joined words can still overflow a narrow container.

Another alternative is to render the final two words in a React span with white-space set through a JSX style object. This also avoids building an HTML string from the content:

const formattedLastWords = (  <span style={{ whiteSpace: 'nowrap' }}>    {words[totalWords - 2]} {words[totalWords - 1]}  </span>);

Whether you chose to use nobr or white-space, both achieve the same effect and this approach works well. In practice though, there will always be edge cases where twoword wrapping is less elegant onscreen, and in these situations, we fall back to the designerdevelopercontent compromise. As a brief example, where I use this for article titles on my blog page, I found that there were occasions where the length of the final word meant that pulling it down onto the next line along with its preceding compatriot, left the text looking misbalanced:

Screenshot of three different grid items on the johnkavanagh.co.uk blog demonstrating wrapping the last two words to avoid an orphan.

In my case, this was easily resolved by adjusting my utility function to first measure the number of letters in the final word, before deciding whether to inject a nonbreaking span or not. However, this does also add more unnecessary complexity to something that you could probably argue is superfluous in modern, responsive, websites anyway.


Planning a platform change?

I help teams make difficult platform work clearer, from architecture decisions and migrations to launch recovery, performance, and search visibility.