webdevpuneet.com

Bootstrap Code Block With Copy + Line Numbers — Free HTML CSS JS Snippet

Bootstrap Code Block With Copy + Line Numbers · Layouts · Plain HTML, CSS & JS · Live preview

CategoryLayouts

Copy & paste

Source Code

<div class="container py-5 d-flex justify-content-center">
  <div class="card bscode-card">
    <div class="bscode-header">
      <span class="small fw-semibold">install.sh</span>
      <button type="button" class="btn btn-sm btn-outline-light" id="bscodeCopy">Copy</button>
    </div>
    <div class="bscode-body">
      <div class="bscode-gutter" id="bscodeGutter"></div>
      <pre class="bscode-pre" id="bscodePre"></pre>
    </div>
  </div>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month, 7 days free), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Line numbers and code lines are generated from the same array, so they can never fall out of sync
Lightweight line-based highlighting for comments and quoted strings, no external syntax highlighter required
Copy grabs the original plain-text source array, never the rendered, HTML-tagged markup
The gutter and code pane scroll independently, so long lines don't push line numbers out of view
A file-name header bar gives the block real context, like a familiar code editor tab

About this UI Snippet

Bootstrap Code Block With Copy + Line Numbers — HTML, CSS & JavaScript

Screenshot of the Bootstrap Code Block With Copy + Line Numbers snippet rendered live

Keeping the line-number gutter and the code perfectly aligned is the entire design challenge here, and this snippet solves it by generating both from the exact same CODE array — gutter.innerHTML maps over CODE.length to produce sequential numbers, and pre.innerHTML maps over the same array to render each line, so a gutter number and its code line can never drift apart even if lines are added or removed, since both are derived from one array's length and index rather than counted separately by hand.

Highlighting is deliberately minimal and line-based: highlight() checks whether a trimmed line starts with # to color it as a comment, and separately wraps any double-quoted text in a string-colored span — good enough for a shell script or a config snippet without pulling in a full tokenizing syntax highlighter for a handful of lines.

The important correctness detail is what "Copy" actually copies: CODE.join('\n') — the original, plain-text array — not the DOM's rendered innerHTML. Copying rendered HTML would paste literal <span class="bscode-comment"> tags into whatever the user pastes into; copying from the source array guarantees the clipboard always holds exactly the real code, with no highlighting markup ever leaking into it.

Step by step

How to Use

  1. 1
    Load the snippetA dark code block appears with line numbers 1 through 9 in the gutter, comments and quoted strings colored differently from plain code.
  2. 2
    Scroll the code horizontally if a line is longThe gutter stays fixed in place while only the code pane scrolls, since they're two separate flex children.
  3. 3
    Click "Copy"The button briefly reads "Copied!" before reverting, and the clipboard holds the plain script text with no HTML markup in it.
  4. 4
    Paste it anywhereIt pastes as clean, runnable shell script text, line numbers and coloring both correctly excluded.

Real-world uses

Common Use Cases

DEV
Documentation, README pages, and setup guides
Pairs with bootstrap-copy-to-clipboard-feedback for the same core copy interaction applied to a single value instead of a whole script.
API documentation showing example requests
Show a curl command or SDK usage example exactly as a developer would want to copy and run it.
Learning to keep derived UI in sync from one source
The gutter-from-array technique here generalizes to any UI where two visual elements must always describe the same underlying list.

Got questions?

Frequently Asked Questions

For a short, illustrative code block, a full tokenizer is often more weight than the content warrants — the line-based comment/string check here covers the common visual cases with zero dependencies, though swapping in highlight.js is a reasonable upgrade for genuinely complex multi-language code.

Nothing else needs to change — both the gutter and the code pane re-derive their length and numbering from CODE.length automatically the next time the page loads.

No — CODE.join('\n') copies only the actual script content; the numbers exist purely in the separate gutter element and were never part of the copied text to begin with.

Yes. Keep CODE as a plain array, map it to both the gutter numbers and the highlighted lines in the render function, and keep the Copy handler joining the original array rather than reading back from the rendered DOM.