Reading code is easier when you have line numbers, but how can you show line numbers in a <pre> tag? This can easily be solved with a few lines of JS and CSS, no need for a big external library.

Reading code is easier when you have line numbers, but how can you show line numbers in a <pre> tag? This can easily be solved with a few lines of JS and CSS, no need for a big external library.

JS:

function addLineNumbersToPres() {
  const pres = document.querySelectorAll('pre')
  pres.forEach((pre) => {
    const lineNumberWrapper = document.createElement('span')
    lineNumberWrapper.classList.add('pre-line-numbers')

    const preLines = pre.textContent.split('\\n').length
    for (let i = 0; i < preLines - 1; i++) {
      const span = document.createElement('span')
      span.appendChild(document.createTextNode(i))
      lineNumberWrapper.appendChild(span)
    }

    pre.insertBefore(lineNumberWrapper, pre.firstChild)
  })
}

This changes the HTML for the <pre> tag to look something like this:

<pre>
  <span class="pre-line-numbers">
    <span>0</span>
    <span>1</span>
    <span>2</span>
    <span>3</span>
    <span>4</span>
    <span>5</span>
  </span>
  <code>
    // Code comes here
  </code>
<pre>

Now for the styling.

CSS:

pre {
  position: relative;
  width: 100%;
  overflow: auto;
  display: grid;
  grid-template-columns: min-content max-content;
}

pre .pre-line-numbers {
  display: flex;
  flex-direction: column;
  height: 100%;
  text-align: right;
  user-select: none;
}

Extra: According to caniuse.com user-select without prefixes is only supported by 50-70% of browsers at the time of writing, so here's the prefixed properties if you want to add them:

pre .pre-line-numbers {
  -webkit-user-select: none;
  -khtml-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
}

What about syntax highlighting?

Syntax highlighting is much more complicated to solve, but maybe I'll make a post about it one day. For now my <pre> tags remain monocolored.