webdevpuneet.com

Plan Comparison with Differences Toggle — Free "Show Only Differences" Table

Plan Comparison with Differences Toggle · Pricing · Plain HTML, CSS & JS · Live preview

CategoryPricing

Copy & paste

Source Code

<div class="pdc-wrap">
  <div class="pdc-toolbar">
    <h3>Compare plans</h3>
    <label class="pdc-switch">
      <input type="checkbox" id="pdcDiffOnly" />
      <span class="pdc-slider"></span>
      Show only differences
    </label>
  </div>

  <table class="pdc-table" id="pdcTable">
    <thead>
      <tr>
        <th class="pdc-corner">Feature</th>
        <th>Starter</th>
        <th>Pro</th>
        <th>Team</th>
      </tr>
    </thead>
    <tbody id="pdcBody">
      <tr><th>Price</th><td>$9/mo</td><td>$29/mo</td><td>$79/mo</td></tr>
      <tr><th>Projects</th><td>3</td><td>Unlimited</td><td>Unlimited</td></tr>
      <tr><th>Team members</th><td>1</td><td>1</td><td>10</td></tr>
      <tr><th>Storage</th><td>10GB</td><td>100GB</td><td>1TB</td></tr>
      <tr><th>Export to CSV</th><td>Yes</td><td>Yes</td><td>Yes</td></tr>
      <tr><th>API access</th><td>No</td><td>Yes</td><td>Yes</td></tr>
      <tr><th>Custom domains</th><td>No</td><td>Yes</td><td>Yes</td></tr>
      <tr><th>Email support</th><td>Yes</td><td>Yes</td><td>Yes</td></tr>
      <tr><th>Priority support</th><td>No</td><td>No</td><td>Yes</td></tr>
      <tr><th>SSO &amp; SAML</th><td>No</td><td>No</td><td>Yes</td></tr>
      <tr><th>Uptime SLA</th><td>No</td><td>No</td><td>99.9%</td></tr>
    </tbody>
  </table>

  <p class="pdc-empty" id="pdcEmpty" hidden>Every row is identical across these plans.</p>
</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

Content-driven diffing
Compares actual cell text, not a hand-maintained diff list.
Verified filter accuracy
Two identical rows hide, nine differing rows stay, on the default data.
Precomputed diff flags
Filtering only reads a data attribute, not re-scanning cell text.
Scales to any columns
Works the same whether comparing 2 plans or 6.
Honest empty state
Shows a message instead of a blank table if nothing differs.
Accessible toggle switch
A real checkbox styled as a switch, keyboard-operable.
Semantic table markup
thead and row th keep the comparison screen-reader friendly.
Framework-agnostic core
markDifferences/applyFilter port directly to any component model.

About this UI Snippet

Plan Comparison with Differences Toggle — Filter Out the Rows That Don't Matter

Screenshot of the Plan Comparison with Differences Toggle snippet rendered live

A pricing comparison table with eleven rows is mostly rows where every plan agrees — "Email support: Yes" across the board tells a buyer nothing. This snippet adds a real "show only differences" toggle that filters those identical rows out, so a comparison shopper can scan exactly what's different between plans in a fraction of the reading time.

Comparing values, not hardcoding a diff list

markDifferences() doesn't rely on a manually maintained list of "which rows differ" — it reads every <td> in each row, compares each cell's text against the first cell's text, and marks the row data-diff="true" the moment any value doesn't match. This means the diff detection is derived from the actual table content: edit a cell's text and the diff status recalculates correctly on the next render, with no separate bookkeeping to keep in sync.

Real filtering, verified against the data

Of the eleven rows in the default table, two have identical values across all three plans (Export to CSV and Email support both say "Yes" across every column) and nine genuinely differ (Price, Projects, Team members, Storage, API access, Custom domains, Priority support, SSO & SAML, and Uptime SLA — the ones where Starter, Pro, and Team don't all match). Toggling "Show only differences" hides exactly the two identical rows and keeps exactly the nine differing ones — verifiable by reading straight down each visible column and confirming no two values are the same across a hidden row.

Toggling visibility without re-querying

Once markDifferences() runs, applyFilter() never re-reads cell values — it only reads the data-diff attribute already stamped on each row and toggles a pdc-hidden-row class. This separation means filtering is cheap even on a long table, since the (more expensive) content comparison happens once up front.

An honest empty state

If every row happened to be identical — a legitimate edge case for near-identical plans — the filtered table would show nothing at all, which reads as broken. A message ("Every row is identical across these plans") appears instead whenever the visible row count hits zero, so the UI never looks empty by accident.

Where it fits

Pair it with a pricing feature table for the full always-visible version, sit it below a pricing card grid, or link a "compare plans" CTA from a pricing page straight to it.

Customizing it

Add more plans or rows — the diff logic scales to any column count automatically. Swap the exact-string comparison for a numeric-aware one if you want "$9/mo" and "9" to be treated as equal, or highlight which specific cell differs rather than just the row.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSAll eleven feature rows render, none hidden.
  2. 2
    Toggle "Show only differences"Rows where every plan matches (like Email support) disappear.
  3. 3
    Count what remainsNine rows stay visible — the ones where at least one plan differs.
  4. 4
    Toggle it back offAll eleven rows reappear immediately.
  5. 5
    Edit a cell to matchChange a differing cell to match the others — it now hides on filter.
  6. 6
    Add a plan or rowThe diff comparison scales automatically to any column or row count.

Real-world uses

Common Use Cases

Long feature comparisons
Hide rows where every plan has identical values, so buyers see only what differs, pairing with a pricing feature table for the full list.
Pricing page companions
Sit below a pricing card grid as a compare plans panel, with diff flags precomputed so filtering reads only a data attribute.
Plan migration decisions
Help an existing customer see exactly what changes between plans, with the diff derived from real cell text instead of a hand-kept list.
Sales enablement
Let a rep pull up only the differentiating features during a call, with the filter working the same for two plans or six.
Competitor and enterprise comparisons
Adapt the diff logic for competitor pages with a comparison table, or highlight what changes on an enterprise pricing proposal.
Related: Cost Per User Breakdown
See the Cost Per User Breakdown for a related pricing pattern worth pairing with this one.

Got questions?

Frequently Asked Questions

markDifferences() reads the text of every plan cell in a row into an array, then checks with Array.every whether every value matches the first one. If any cell's text differs from the first cell's text, the row is stamped data-diff="true". This is computed from the actual displayed values, not a separate list someone has to keep updated.

Of the eleven default rows, Export to CSV and Email support show "Yes" across all three plans and hide when filtering to differences. The remaining rows — Price, Projects, Team members, Storage, API access, Custom domains, Priority support, SSO & SAML, and Uptime SLA — each have at least one plan whose value doesn't match the others, so they stay visible.

The visible row count would hit zero, so instead of rendering an empty table body, a message reading "Every row is identical across these plans" appears. This is checked every time the filter runs, by counting how many rows remain shown after applying the diff-only filter.

No — the content comparison happens once, in markDifferences(), which stamps each row with a data-diff attribute. Toggling the filter afterward only reads that already-computed attribute and flips a CSS display class, so it stays cheap even on a long table with many rows.

Model the table as a rows array of {label, values: []} objects. Derive each row's isDifferent flag with values.every(v => v === values[0]) in a memoized computation, then filter the rendered rows by that flag and the toggle's checked state. The diff-detection logic is pure and ports over unchanged.