Lumis Docs
Migrate

HTML line markup

Update CSS, custom formatters, and copy buttons for content-only line spans.

Use this guide if your CSS or custom formatter expects a <div> for each line, or a line terminator inside each wrapper.

The Rust, JavaScript, Elixir, and CLI HTML formatters use <span class="l-line" data-line="N">. Each span holds only its content. A \n text node separates consecutive lines, with nothing after the last span:

<pre class="lumis"><code class="language-plaintext" translate="no" tabindex="0"><span class="l-line" data-line="1">first</span>
<span class="l-line" data-line="2">second</span></code></pre>

Spans are valid phrasing content inside <pre><code> and avoid doubled newlines in innerText. Classes, data-line, highlight classes, and gutter elements are unchanged.

A final LF or CRLF terminates the last line rather than adding an empty numbered line: "a\n" renders one line, "a\n\n" renders two, and empty input renders one empty line. HTML separators are LF. Terminal and BBCode output retain their source terminators.

Custom CSS

Update the bundled theme stylesheet when you update the formatter. If you generate CSS with CssBuilder, build_css, or buildCss, regenerate it. Line layout lists the structural rules included in those stylesheets.

Check your own line rules:

  • Replace selectors such as div.l-line with .l-line.
  • Remove display: block. A block line plus its separating newline renders an extra blank row. Use inline or inline-block lines; code { display: grid } can leave empty lines out of copied text in some browsers.
  • Add box-sizing: border-box if a line has horizontal padding or a border, so it fits within width: 100%.

The bundled layout rule targets span.l-line, so it does not change the block layout of cached HTML that uses divs. Its fit-content width supports both horizontal scrolling and white-space: pre-wrap. Empty rows keep their height.

Layout rules sit in @layer lumis. Unlayered CSS overrides them. If your styles also use layers, declare lumis before those layers; see Tailwind CSS.

HTML Inline and HTML Multi-Themes supply layout styles inline: on highlighted and empty lines, on <code> when lines are highlighted, and on line-number gutters. Disabling highlight colors with style: nil (null in JavaScript) does not disable this layout.

Custom formatters

render_lines_from_events / renderLinesFromEvents returns content-only lines. Remove any terminator stripping from your formatter. wrap_line / wrapLine wraps a line in a span and adds no newline, so join wrapped lines explicitly:

const body = renderLinesFromEvents(source, events, spanAttrs)
.map((line, i) => wrapLine(i + 1, line))
.join('\n');

Apply the line layout CSS if these wrappers need full-width backgrounds. A per-line table, diff view, or stream can use the returned content directly without adding separators.

Copy buttons

Copy the original source when exact text matters. Browsers normalize CRLF, HTML output omits the final terminator, and innerText / textContent include gutter text. user-select: none excludes numbers from selection copy, not from those DOM properties. Chromium can also trim trailing blank rows that contain only unselectable gutters. A source-backed copy button avoids these differences.

On this page