More Layouts Snippets
Code Block — Free HTML CSS JS Snippet
Code Block · Layouts · Plain HTML, CSS & JS · Live preview
What's included
Features
About this UI Snippet
Code Block — Syntax Highlighting, Copy Button, Language Tabs & Line Numbers

Every developer blog, documentation site, tutorial, and technical landing page needs a well-styled code block. Syntax highlighting makes code dramatically more readable — keywords, strings, function names, and comments in distinct colours allow the reader to parse structure visually before reading text. This snippet provides a complete styled code block: a dark terminal frame with macOS-style dots, CSS-based syntax highlighting using span classes, line numbers, a copy-to-clipboard button with success feedback, and language tab switching.
CSS-based syntax highlighting without a library
The syntax highlighting uses CSS classes applied via span elements inline in the HTML: .kw (keywords, purple), .fn (function names, blue), .str (strings, green), .cm (comments, muted grey italic), .num (numbers, orange), .op (operators, light grey). These map to the classic VSCode Dark+ colour scheme that developers recognise immediately. No Prism.js, no Highlight.js — just CSS classes on span elements.
Line numbers with CSS
The line numbers column uses a separate div with textContent set to numbers joined by newlines: lines.map((_,i) => i+1).join('\n'). It uses the same font-family, font-size, and line-height as the code block to ensure perfect vertical alignment. user-select: none prevents accidental line number selection when users copy code.
The copy button feedback pattern
navigator.clipboard.writeText() returns a Promise. On resolve, the button label changes to "Copied!" and a .copied class applies a green colour scheme. A setTimeout resets both after 2 seconds. The Clipboard API is available in all modern browsers over HTTPS. The code text is extracted via code element textContent, which strips HTML tags from the span elements.
Language tab switching
Three SNIPPETS objects hold pre-highlighted HTML for each language. setLang(lang) updates the active tab, re-renders the code and line numbers, and updates the language label. The pre-highlighted HTML approach avoids runtime parsing — the highlighting is applied at author time.
Adapting for your content
Replace the SNIPPETS objects with your own code. Apply the .kw, .fn, .str, .cm, .num span classes to your code tokens. For automatic syntax highlighting at scale, use Prism.js or Shiki server-side to generate the highlighted HTML that replaces the span-based approach in this snippet.
Extending with a filename tab
Add a filename display between the browser dots and the language label: <span class="cb-filename">api/users.js</span>. This is standard in documentation sites where the same code block appears across multiple files. Update via JavaScript when the language tab changes: setLang() updates both the lang-label and filename spans simultaneously.
Build with AI
Build, Understand, Optimize, and Extend It With AI
Rather than assuming the pre-baked HTML strings in SNIPPETS are just decoration, paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly why the code is stored as HTML strings with span tags already embedded rather than tokenized at render time, and why copyCode() reads textContent instead of innerHTML to get the clipboard value. The same assistant can help you assess the tradeoffs — ask whether hand-authoring highlighted HTML like this scales past three small snippets, and at what point switching to a build-time highlighter like Shiki becomes worth the added tooling. It's also a good partner for extending the block: ask it to add line-highlighting for specific lines via a data attribute, add a fourth language tab, or wire the copy button to a click-tracking event so you can measure which snippet gets copied most. Treat the code less like a finished artifact and more like a starting point for a conversation.
Prompt to recreate it
Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:
Build a terminal-style "code block" with language tabs in plain HTML, CSS, and JavaScript — no syntax-highlighting library required, but written so a real one could later replace the markup approach.
Requirements:
- Store each language's example as pre-authored HTML source (a template string containing span elements with semantic class names like keyword, function, string, comment, number, operator) rather than plain unstyled text, so switching languages swaps in a complete pre-highlighted block via innerHTML.
- A header bar styled like a terminal window: three colored circular dots (red, yellow, green) on the left, a centered language label showing the currently active language's display name, and on the right a copy button plus a small set of language-tab buttons.
- Clicking a language tab must update that tab's active visual state, swap the displayed code and line numbers to match the newly selected language's stored snippet, and update the centered language label text.
- A separate line-numbers column, generated by splitting the current snippet's raw text on newlines and rendering sequential numbers, using the exact same font family, font size, and line height as the code area so the numbers stay vertically aligned with their corresponding code lines, and marked non-selectable.
- The copy button must extract the code element's textContent (not innerHTML) so the highlighting span tags are stripped and only the plain, pasteable source text is copied, using the Clipboard API with a hidden-textarea execCommand fallback, and must show a temporary green "Copied!" state that reverts to "Copy" after about two seconds.
- Apply a consistent, VSCode-like color palette across the span classes (keywords, function names, strings, comments, numbers, operators) so all three language examples look visually cohesive despite being independently authored.Step by step
How to Use
- 1Click the language tabs to switch code examplesClick JS, Python, or TS to switch between language examples. The code, line numbers, and language label update immediately. Each language shows the same fetch-and-render logic in different syntax.
- 2Click Copy to copy the code to clipboardClick the Copy button to copy the current code to clipboard. The button turns green and shows "Copied!" for 2 seconds, then resets. The textContent is copied without HTML tags.
- 3Replace the code contentUpdate the code strings in the SNIPPETS object. Apply .kw, .fn, .str, .cm, .num CSS classes via span elements to add syntax highlighting to your own code. Or paste plain code without spans for an unstyled code block.
- 4Add or remove language tabsAdd a new entry to SNIPPETS and a matching .lang-tab button with data-lang and onclick="setLang('newlang')". Remove unused language objects and their tab buttons.
- 5Use Shiki or Prism.js for automatic highlightingFor production documentation sites, replace the manual span approach with server-side highlighting. In Next.js, use Shiki createHighlighter() to generate highlighted HTML from raw code strings at build time. This snippet's CSS colour variables stay compatible with both approaches.
- 6Export in your formatClick "HTML" for a standalone file, "JSX" for a React component accepting code and language props, or "Tailwind" for a React + Tailwind CSS version.
Real-world uses
Common Use Cases
Got questions?
Frequently Asked Questions
The copy function reads code element textContent (not innerHTML): const text = document.getElementById("cb-code").textContent. textContent returns only the visible characters without any HTML markup — the span tags used for syntax highlighting are stripped automatically. This gives the user clean, pasteable code without any markup artifacts.
For production use, use a server-side highlighting library. In Next.js: import { createHighlighter } from "shiki"; const hl = await createHighlighter({ themes: ["github-dark"], langs: ["javascript"] }); const html = hl.codeToHtml(code, { lang: "javascript", theme: "github-dark" }). Set the returned HTML as innerHTML of your code element. The Shiki output is compatible with this code block's CSS structure — just remove the manual span classes and use Shiki's classes instead.
Add a data-highlight attribute listing which lines to highlight: <pre data-highlight="3,7,8">. In JavaScript, after render(), read the attribute: const highlighted = pre.dataset.highlight?.split(",").map(Number) || []. Then wrap those line numbers in the code HTML: split the code by newline, wrap lines at highlighted indexes in <span class="hl-line">...</span>, rejoin. Add .hl-line { background: rgba(99,102,241,0.1); display: block; margin: 0 -16px; padding: 0 16px; } to the CSS.
Click "JSX" to download. Accept code (string), lang (string), and language (display label string) as props. Use dangerouslySetInnerHTML={{ __html: highlightedCode }} for the code element to render the pre-highlighted HTML. In Next.js, use Shiki in getStaticProps or a Server Component to generate the highlighted HTML at build time, passing it as a prop. For React without SSR, use Prism.js or highlight.js in a useEffect to highlight after mount.