JSFiddle - React, Tailwind, and code Playground

HTML

<!DOCTYPE html>
<html lang="en">
<head>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <textarea id="dynamic-text-input"></textarea>
  <script src="script.js"></script>
</body>
</html>

CSS

#dynamic-text-input {
  width: 100px; /* Set your desired width here */
  border: 1px solid #ccc;
  padding: 5px;
  font-family: monospace;
  overflow: hidden;
}

JavaScript

const MAX_LINES = 3; // Maximum number of lines allowed

const textInput = document.getElementById('dynamic-text-input');

function getLineHeight(elem) {
    let computedStyle = window.getComputedStyle(elem);
    let lineHeight = computedStyle.getPropertyValue('line-height');
    let lineheight;
    
    if (lineHeight === 'normal') {
        let fontSize = computedStyle.getPropertyValue('font-size'); // Get Font Size
        lineheight = parseFloat(fontSize) * 1.2; // 'normal' Line Height Equals To 120% Of Font Size In Most Browsers
    } else {
        lineheight = parseFloat(lineHeight); // The Line Height That Is Not 'normal'
    }
    
    return lineheight;
}

function resizeDiv(event) {
  const lineHeight = getLineHeight(textInput);
  const lines = Math.max(1, Math.ceil(textInput.value.length/13));

  textInput.style.minHeight = `${Math.min(lines, MAX_LINES)*lineHeight}px`;
  textInput.style.maxHeight = `${Math.min(lines, MAX_LINES)*lineHeight}px`;
  textInput.style.height = `${Math.min(lines, MAX_LINES)*lineHeight}px`;
  if (lines > MAX_LINES) {
  	/* event.preventDefault(); */
    textInput.readOnly = true;
  }
}

// Initial resize on load
resizeDiv();

// Add event listener for text changes
textInput.addEventListener('input', resizeDiv);
/* textInput.addEventListener('keydown') */