JSFiddle - React, Tailwind, and code Playground
by jolleekin
HTML
<textarea id="textarea" rows="5"></textarea>
<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 */
}
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);
}
$('#textarea').oninput = function(e) {
$('#lineCount').textContent = countLines(e.target);
}