webdevpuneet.com

Code Comparison Block — Before After Diff UI HTML CSS

Code Comparison Block · Layouts · Plain HTML, CSS & JS · Live preview

CategoryLayouts

Copy & paste

Source Code

<div class="page">
  <div class="comp-header">
    <h2 class="comp-title">Before <span class="arrow">→</span> After</h2>
    <p class="comp-sub">Refactored component: replaced imperative DOM manipulation with declarative React state.</p>
  </div>

  <div class="comp-grid">
    <!-- BEFORE panel -->
    <div class="code-panel panel-before">
      <div class="panel-header">
        <div class="panel-label bad">Before</div>
        <div class="header-right">
          <span class="lang-badge">JavaScript</span>
          <button class="copy-btn" onclick="copyCode(this, 'before')" aria-label="Copy code">
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
            Copy
          </button>
        </div>
      </div>
      <div class="code-block" id="before"><div class="cl"><span class="ln">1</span>  <span class="kw">function</span> <span class="fn">UserProfile</span>() &#123;</div>
<div class="cl"><span class="ln">2</span>    <span class="kw">const</span> btn = document.<span class="fn">getElementById</span>(<span class="str">'editBtn'</span>);</div>
<div class="cl"><span class="ln">3</span>    <span class="kw">const</span> form = document.<span class="fn">getElementById</span>(<span class="str">'profileForm'</span>);</div>
<div class="cl"><span class="ln">4</span>    <span class="kw">const</span> display = document.<span class="fn">getElementById</span>(<span class="str">'displayName'</span>);</div>
<div class="cl"><span class="ln">5</span> </div>
<div class="cl bl"><span class="ln">6</span>    btn.<span class="fn">addEventListener</span>(<span class="str">'click'</span>, () => &#123;</div>
<div class="cl bl"><span class="ln">7</span>      <span class="kw">if</span> (form.style.display === <span class="str">'none'</span>) &#123;</div>
<div class="cl bl"><span class="ln">8</span>        form.style.display = <span class="str">'block'</span>;</div>
<div class="cl bl"><span class="ln">9</span>        display.style.display = <span class="str">'none'</span>;</div>
<div class="cl bl"><span class="ln">10</span>       btn.textContent = <span class="str">'Cancel'</span>;</div>
<div class="cl bl"><span class="ln">11</span>     &#125; <span class="kw">else</span> &#123;</div>
<div class="cl bl"><span class="ln">12</span>       form.style.display = <span class="str">'none'</span>;</div>
<div class="cl bl"><span class="ln">13</span>       display.style.display = <span class="str">'block'</span>;</div>
<div class="cl bl"><span class="ln">14</span>       btn.textContent = <span class="str">'Edit'</span>;</div>
<div class="cl bl"><span class="ln">15</span>     &#125;</div>
<div class="cl bl"><span class="ln">16</span>   &#125;);</div>
<div class="cl"><span class="ln">17</span> &#125;</div></div>
    </div>

    <!-- AFTER panel -->
    <div class="code-panel panel-after">
      <div class="panel-header">
        <div class="panel-label good">After</div>
        <div class="header-right">
          <span class="lang-badge">React</span>
          <button class="copy-btn" onclick="copyCode(this, 'after')" aria-label="Copy code">
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
            Copy
          </button>
        </div>
      </div>
      <div class="code-block" id="after"><div class="cl"><span class="ln">1</span>  <span class="kw">function</span> <span class="fn">UserProfile</span>() &#123;</div>
<div class="cl"><span class="ln">2</span>    <span class="kw">const</span> [editing, setEditing] = <span class="fn">useState</span>(<span class="bool">false</span>);</div>
<div class="cl"><span class="ln">3</span> </div>
<div class="cl gl"><span class="ln">4</span>    <span class="kw">return</span> (</div>
<div class="cl gl"><span class="ln">5</span>      &lt;<span class="tag">div</span>&gt;</div>
<div class="cl gl"><span class="ln">6</span>        &#123;editing</div>
<div class="cl gl"><span class="ln">7</span>          ? &lt;<span class="tag">ProfileForm</span></div>
<div class="cl gl"><span class="ln">8</span>              onSave=&#123;() =&gt; <span class="fn">setEditing</span>(<span class="bool">false</span>)&#125; /&gt;</div>
<div class="cl gl"><span class="ln">9</span>          : &lt;<span class="tag">DisplayName</span> /&gt;</div>
<div class="cl gl"><span class="ln">10</span>        &#125;</div>
<div class="cl gl"><span class="ln">11</span>        &lt;<span class="tag">button</span></div>
<div class="cl gl"><span class="ln">12</span>          onClick=&#123;() =&gt; <span class="fn">setEditing</span>(e =&gt; !e)&#125;&gt;</div>
<div class="cl gl"><span class="ln">13</span>          &#123;editing ? <span class="str">'Cancel'</span> : <span class="str">'Edit'</span>&#125;</div>
<div class="cl gl"><span class="ln">14</span>        &lt;/<span class="tag">button</span>&gt;</div>
<div class="cl gl"><span class="ln">15</span>      &lt;/<span class="tag">div</span>&gt;</div>
<div class="cl gl"><span class="ln">16</span>    );</div>
<div class="cl"><span class="ln">17</span> &#125;</div></div>
    </div>
  </div>

  <!-- Diff summary -->
  <div class="diff-summary">
    <div class="diff-stat removed"><span class="diff-num">−8</span> lines removed</div>
    <div class="diff-stat added"><span class="diff-num">+11</span> lines added</div>
    <div class="diff-note">Declarative state eliminates 5 direct DOM queries</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), 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

CSS syntax token highlighting
.kw (purple), .fn (blue), .str (green), .bool (orange), .tag (pink) — VS Code Dark+ colours applied via span wrappers, no external library.
Full-width diff line markers
.bad-line and .good-line use display:block + negative margin to extend the background and border accent across the full panel width.
Copy with line number strip
replace(/^\d+\s*/gm, '') strips leading line numbers from innerText — pastes clean code without the number prefix.
Panel colour coding
.panel-before has a red border tint, .panel-after has a green border tint — at-a-glance bad/good visual identity for each panel.
Language badge
.lang-badge shows the language or framework per panel (JavaScript / React) — important when comparing cross-language rewrites.
Diff summary bar
Lines added/removed counts with a plain-English description — matches the GitHub pull request diff summary format.
Responsive stacking
Two-column grid on desktop, single column on mobile — code panels stack vertically on small screens for full readability.
Dark theme base
background: #0d1117 (GitHub dark) for code blocks, #1e293b (slate-800) for headers — the standard developer tool dark colour scheme.

About this UI Snippet

Code Comparison Block — CSS Syntax Highlight, Diff Line Markers & Copy-to-Clipboard

Screenshot of the Code Comparison Block snippet rendered live

Code comparison blocks are essential in developer tooling, technical documentation, tutorial sites, and code review interfaces — anywhere you need to show what changed and why. This snippet builds a production-quality before/after comparison layout with two dark-theme code panels, CSS-based syntax highlighting, red/green diff line markers with left border accents, copy-to-clipboard buttons, language badges, and a diff summary bar showing lines added and removed.

Technical blog posts, refactoring guides, changelog pages, and code review tools all need a clear visual diff format. The challenge is communicating change at a glance: readers must immediately see what was removed (red), what was added (green), and understand the structural difference — without reading every line. The left border accent on diff lines mirrors the GitHub and GitLab diff viewer pattern that developers already recognise.

CSS syntax highlighting without a library

Syntax highlighting is achieved with HTML <span> elements wrapping token groups, each with a colour class: .kw (keywords, purple #c084fc), .fn (function names, blue #60a5fa), .str (strings, green #86efac), .bool (booleans, orange #f97316), .tag (JSX tags, pink #f472b6). This manual approach is intentional for a snippet — no external library dependency. For a production code editor, use a library like Prism.js or highlight.js. The colour palette is derived from the VS Code Dark+ theme, the most widely-used editor colour scheme.

Diff line markers

Lines marked with .bad-line or .good-line use a display: block override to make the span fill the full line width, combined with negative margin (margin: 0 -16px; padding: 0 16px) to extend the background colour into the panel padding — matching GitHub's diff viewer behaviour. The left border (border-left: 2px solid) provides a secondary "this line changed" indicator for colour-blind accessibility. Line numbers also shift colour: red-tinted for removed lines, green-tinted for added lines.

Copy-to-clipboard with line number stripping

The copy function uses pre.innerText to get the rendered text, then strips line numbers with replace(/^\d+\s*/gm, '') — a multiline regex that removes the leading number + whitespace from each line. The result is clean, pasteable code. The Clipboard API (navigator.clipboard.writeText) is modern and requires HTTPS in production. The button transitions to a green "Copied!" state for 2 seconds, then reverts — the same pattern used in code block and copy button snippets.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSTwo side-by-side dark code panels appear: "Before" (red border) showing imperative DOM code, and "After" (green border) showing the React state equivalent.
  2. 2
    Read the diff highlightsRed-background lines with a left red border show removed/bad code. Green-background lines with a left green border show the new/good code.
  3. 3
    Click Copy on either panelThe button copies the code to clipboard with line numbers stripped. It turns green and shows "Copied!" for 2 seconds, then resets.
  4. 4
    Read the diff summary barBelow the panels: −8 lines removed (red), +11 lines added (green), and a plain-English description of the change.
  5. 5
    Update code contentReplace the <code> content inside each <pre>. Wrap tokens in <span class="kw">, <span class="fn">, <span class="str"> etc. for highlighting.
  6. 6
    Mark diff linesWrap any line in <span class="bad-line">...</span> for red highlighting or <span class="good-line">...</span> for green highlighting.

Real-world uses

Common Use Cases

Technical blog posts and tutorials
Show before/after code in refactoring articles, migration guides, and "from X to Y" tutorials. The diff highlights make the change immediately scannable.
Changelog and release notes pages
Breaking change documentation benefits from a side-by-side diff showing the old API pattern next to the new one.
Code review UI in developer tools
Internal tooling, PR preview tools, and code quality dashboards use diff blocks to highlight the specific changes in a pull request.
Design system migration guides
Component library upgrade guides (v1 → v2) show the old usage pattern next to the new one — helps developers migrate without reading the full docs.
Interview prep and algorithm explanations
Technical interview prep sites compare inefficient and optimised solutions side-by-side with time/space complexity notes in the diff summary.
AI code review tools
AI-generated code improvement suggestions shown as before/after diffs — the format is familiar and immediately actionable for developers.
Related: CSS if() Conditional Demo
See the CSS if() Conditional Demo for a related layouts pattern worth pairing with this one.

Got questions?

Frequently Asked Questions

Replace the manual span markup with Prism.js: add <script src="prism.js"> and use <code class="language-javascript">. Prism tokenises the code automatically. For a build-time solution, use Shiki (used by VitePress and Astro) which renders highlighted HTML at build time — zero client-side JS.

The <pre> already has overflow-x: auto. For very long lines, ensure the .code-block has white-space: pre (not pre-wrap) so lines don't wrap. Add min-width: 0 to the .code-panel in the grid to prevent flex/grid overflow.

Remove the grid and use a single <pre> with both .bad-line (red, − prefix) and .good-line (green, + prefix) lines interleaved. Add a + or − character before each changed line's content, matching the git diff output format.

Create a CodePanel component accepting {title, language, code, variant} where code is a pre-highlighted HTML string (from Shiki/Prism) set via dangerouslySetInnerHTML. The parent CodeComparison takes {before, after, summary} props and renders two CodePanel instances side-by-side.