JSFiddle - React, Tailwind, and code Playground

HTML

<h1>Full-word multi-line word-wrap with ellipsis</h1>

<p id="source">
Measures source text, slices it into lines that do not exceed the container width.  Each line breaks cleanly on a space.  Restricts to the specified number of lines.  Appends last line with an ellipse.  Last word in output is a complete word.
</p>
<div id="wourcewidth"></div>
<hr/>
Output:
<p id="ellipsis"></p>
<hr/>
<div id="ellipsismaxwidth"></div>
<div id="ellipsismaxlines"></div>

JavaScript

var maxWidth = 300;
var maxLines = 3;

// ----------------------------------------------

function getTextWidth(text, font) {
    var canvas = getTextWidth.canvas || 
        (getTextWidth.canvas = document.createElement("canvas"));
    var context = canvas.getContext("2d");
    context.font = font;
    var metrics = context.measureText(text);
    return metrics.width;
};

var startIndex = 0;
var ellipsisText = "";

// Get font style and size for source text
var $objCss = $("#source").css("font");

// Split source text into array on spaces.
var arr = $("#source").text().split(" ");

// Show output of how wide source text is.
$("#sourcewidth").text("Source text width: " + getTextWidth($("#source").text(), $objCss) + " px"); 

// Get width of space
var spaceWidth = getTextWidth(" ", $objCss);

// Get width of ellipsis
var ellipsisWidth = getTextWidth(" ...", $objCss);

// For each line
for (var o = 0; o < maxLines; o++) {
    var newLine = "";
    var newLineWidth = 0;

    ellipsisWidth = (o + 1 == maxLines ? ellipsisWidth : 0);
    
    // For each word in the array
    for (var i = startIndex; i < arr.length; i++) {
        // Get width of each word.
        var wordWidth = getTextWidth(arr[i], $objCss);
        
        // Append word to newLine
        // Don't allow newLine to be wider than maxWidth
        if ((wordWidth + spaceWidth + newLineWidth + ellipsisWidth) < maxWidth) {
            newLineWidth += (wordWidth + spaceWidth);
            newLine += arr[i] + " ";
            startIndex = i + 1;
            // TODO: Handle words wider than maxWidth
        }
        else {
            break;   
        }
    }
    //console.log(o);
    ellipsisText += (newLine + (o + 1 == maxLines ? " ..." : "<br/>"));
}

// Show ellipsis text
$("#ellipsis").html(ellipsisText);

// Show ellipsis max width
$("#ellipsismaxwidth").html("Max width: " + maxWidth);

// Show ellipsis text
$("#ellipsismaxlines").html("Max lines: " + maxLines);