JSFiddle - React, Tailwind, and code Playground

HTML

<textarea id="textarea" rows="5"></textarea>


<div id="checkWrapNum">Click here</div>
<div id="checkWrapNumArea" class="wordwrap"></div>

<div># lines = <span id="lineCount"></span></div>

CSS

body {
  --line-height: 48px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  font-size: 36px;
  line-height: var(--line-height);
  font-family: 'Segoe UI', 'Roboto Sans', 'Open Sans', Verdana, Tahoma, sans-serif;
  margin: 0;
  height: 100vh;
}

textarea {
  border: 1px solid;
  font: inherit;
  overflow: auto;
  padding: 12px;
  background-attachment: local;
  background-clip: content-box;
  background-image: repeating-linear-gradient(to bottom, transparent 0, transparent calc(var(--line-height) - 1px), rgba(0, 0, 0, .1) calc(var(--line-height) - 1px), rgba(0, 0, 0, .1) var(--line-height));
  background-position-y: 8px; /* 12px */
}

#checkWrapNumArea {
 
}

.wordwrap { 
   white-space: pre-wrap;      /* CSS3 */   
   white-space: -moz-pre-wrap; /* Firefox */    
   white-space: -pre-wrap;     /* Opera <7 */   
   white-space: -o-pre-wrap;   /* Opera 7 */    
   word-wrap: break-word;      /* IE */
}

JavaScript

/** @type {HTMLTextAreaElement} */
var _buffer;

/**
* Returns the number of lines in a textarea, including wrapped lines.
*
* __NOTE__:
* [textarea] should have an integer line height to avoid rounding errors.
*/


function countLines(textarea) {
    if (_buffer == null) {
        _buffer = document.createElement('textarea');
        _buffer.style.border = 'none';
        _buffer.style.height = '0';
        _buffer.style.overflow = 'hidden';
        _buffer.style.padding = '0';
        _buffer.style.position = 'absolute';
        _buffer.style.left = '0';
        _buffer.style.top = '0';
        _buffer.style.zIndex = '-1';
        document.body.appendChild(_buffer);
    }

    var cs = window.getComputedStyle(textarea);
    var pl = parseInt(cs.paddingLeft);
    var pr = parseInt(cs.paddingRight);
    var lh = parseInt(cs.lineHeight);

    // [cs.lineHeight] may return 'normal', which means line height = font size.
    if (isNaN(lh)) lh = parseInt(cs.fontSize);

    // Copy content width.
    _buffer.style.width = (textarea.clientWidth - pl - pr) + 'px';

    // Copy text properties.
    _buffer.style.font = cs.font;
    _buffer.style.letterSpacing = cs.letterSpacing;
    _buffer.style.whiteSpace = cs.whiteSpace;
    _buffer.style.wordBreak = cs.wordBreak;
    _buffer.style.wordSpacing = cs.wordSpacing;
    _buffer.style.wordWrap = cs.wordWrap;

    // Copy value.
    _buffer.value = textarea.value;

    var result = Math.floor(_buffer.scrollHeight / lh);
    if (result == 0) result = 1;
    return result;
}


function $(selector) {
    return document.querySelector(selector);
}

$('#checkWrapNum').onclick = function(e) {
  var span = document.createElement('span');
  span.innerHTML = "test";
	$('#checkWrapNumArea').appendChild(span);
}

$('#textarea').oninput = function(e) {
    $('#lineCount').textContent = countLines(e.target);
}