<textarea>Lorem ipsum dolor sit amet consectetur adipisicing elit. Corporis, minima.
Doloribus voluptatum hic molestiae officia reiciendis, eveniet id quia.
Sunt voluptate nostrum nisi expedita labore dolore deleniti error.
Amet, quibusdam similique. Explicabo obcaecati quod distinctio quaerat.
Nulla temporibus perspiciatis vitae nesciunt consequuntur doloribus quo.
Quasi repudiandae sequi, sint pariatur ipsum sed doloremque.
Veniam, aliquid veritatis. Animi molestias omnis debitis hic.
Fuga repellendus maxime, architecto dolores voluptatem quod dolorum!
Perferendis pariatur distinctio autem minima, alias quibusdam doloribus.
Laborum modi esse consectetur doloremque reprehenderit deserunt fuga.
</textarea>
textarea {
  background-attachment: local;
  background-position: 0 0;
  background-repeat: no-repeat;
  background-size: 5ch 100%;
  border: 1px solid #ccc;
  border-radius: .25rem;
  box-sizing: border-box;
  field-sizing: content;
  font-family: ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, 'DejaVu Sans Mono', monospace;
  font-size: 0.8125rem;
  font-weight: normal;
  line-height: 1.6;
  padding-block: 1.5ch;
  padding-inline: 7ch 2ch;
  resize: vertical;
  width: 100%;
}
function lineNumbers(element, numLines) {
  const bgColor = getComputedStyle(element).borderColor;
  const fillColor = getComputedStyle(element).color;
  const fontFamily = getComputedStyle(element).fontFamily;
  const fontSize = parseFloat(getComputedStyle(element).fontSize);
  const lineHeight = parseFloat(getComputedStyle(element).lineHeight) / fontSize;
  const paddingTop = parseFloat(getComputedStyle(element).paddingTop) / 2;
  const translateY = (fontSize * lineHeight).toFixed(2);

  /* Note: In Safari, deduct `(paddingTop / 10)` from translateY */

  const svg = `<svg xmlns="http://www.w3.org/2000/svg" style="background:${bgColor};">
    <style>
      text {
        fill: hsl(from ${fillColor} h s l / 50%);
        font-family: ${fontFamily};
        font-size: ${fontSize}px;
        line-height: ${lineHeight};
        text-anchor: end;
        translate: 0 calc((var(--n) * ${translateY}px) + ${paddingTop}px);
      }
    </style>
    ${Array.from({ length: numLines }, (_, i) => `<text x="80%" style="--n:${i + 1};">${i + 1}</text>`).join("")}
  </svg>`;

  element.style.backgroundImage = `url("data:image/svg+xml,${encodeURIComponent(svg)}")`;
}

// Example usage
const textarea = document.querySelector("textarea");
lineNumbers(textarea, 50);

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.