Using JavaScript to Avoid Orphans

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 single‑word lines that hang alone at the end of a block of text or paragraph:

I say these are annoying, but really any front‑end developer who has spent a lot of time with hyper‑focused 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 CSS‑based 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 end‑user. 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 tended‑to. For example in the titles of grid‑based listing pages such as Blogs or Product Listings:

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 server‑side rendering, then there is a relatively straightforward solution using JavaScript to join the final two words with a non‑breaking 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 non‑breaking space is ordinary text rather than an HTML injection sink. The old nobr (the 'non‑breaking 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 two‑word wrapping is less elegant on‑screen, and in these situations, we fall back to the designer‑developer‑content 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:

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 non‑breaking 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.