Project

Build an honest product comparison page

Compare three fictional library plans with a semantic table, clear qualifications, and useful native disclosures.

Intermediate14 min readLearn · Practice · Review

Published by HTML Code Runner · AI-assisted material · Independent editorial review pending · Editorial policy

On this page

Project brief

A library offers several fictional membership plans and needs a page that helps readers compare them. Build a clear comparison that answers what each plan includes, what it costs, and which limitations apply. The goal is an informed decision, not a visually crowded collection of promotional claims.

The example compares a free digital plan, a standard borrowing plan, and a family plan. Each feature row has a meaningful label. The page explains the billing period and the fictional nature of its prices, and it keeps important limitations visible. There are no fabricated purchase buttons or claims that one plan is objectively best for everyone.

Begin by writing the comparison as plain text. If a feature label is vague, such as Premium access, define what it means before putting it in a table. A polished grid cannot compensate for unclear or incomparable information.

Learning objectives

Combine semantic HTML, accessible controls, clear reading order, and deliberate browser behavior in a complete small interface. Explain each structural decision, then verify the result with the acceptance checks below.

Prerequisites

Complete the linked lessons before starting. Use a text editor and a browser with developer tools. The provided solution runs entirely in the browser and uses no external libraries or assets.

Design and implementation decisions

The central comparison is a genuine data table: columns identify plans, and rows identify features. Scope values connect the simple headers to their data cells. The caption names the comparison so it remains understandable when reached directly through table navigation.

Text such as Included and Not included is clearer than unexplained colored checkmarks. If icons are added later, retain equivalent text. The table uses horizontal overflow at narrow widths, preserving its row-column relationships rather than converting cells into visually reordered fragments with unclear semantics.

Supporting disclosures answer billing and eligibility questions. The most important condition, that prices are fictional and no purchase is offered, remains visible. A real commercial comparison should use accurate current terms and a real checkout workflow rather than presenting a demonstration as a functioning store.

Build it step by step

  1. List the plans and choose genuinely comparable features.
  2. Write a caption and column headers for each plan.
  3. Use row header cells for price and feature names.
  4. State the billing period directly in the price row.
  5. Add visible qualifications and a short FAQ.
  6. Test table navigation, narrow screens, and the page without styling.

Runnable solution

HTML structure

<a class="skip" href="#main">Skip to plan comparison</a><header><p><strong>North Library</strong></p><nav aria-label="Page sections"><a href="#plans">Compare plans</a><a href="#terms">Plan details</a></nav></header><main id="main"><h1>Choose a plan for the way you read</h1><p>Compare digital access and borrowing options. These plans and prices are fictional learning examples; no purchase is available.</p><section id="plans" aria-labelledby="plans-title"><h2 id="plans-title">The details, side by side</h2><div class="table-scroll"><table><caption>Fictional membership plan comparison</caption><thead><tr><th scope="col">Feature</th><th scope="col">Digital</th><th scope="col">Standard</th><th scope="col">Family</th></tr></thead><tbody><tr><th scope="row">Monthly price</th><td>₹0</td><td>₹100 per month</td><td>₹180 per month</td></tr><tr><th scope="row">Digital catalogue</th><td>Included</td><td>Included</td><td>Included</td></tr><tr><th scope="row">Physical books at once</th><td>Not included</td><td>4 books</td><td>10 books across the household</td></tr><tr><th scope="row">Workshop bookings</th><td>Public sessions</td><td>Public and member sessions</td><td>Public and member sessions</td></tr><tr><th scope="row">Named readers</th><td>1</td><td>1</td><td>Up to 4</td></tr></tbody></table></div></section><section id="terms" aria-labelledby="terms-title"><h2 id="terms-title">Understand the plan details</h2><p>All physical borrowing remains subject to item availability. A plan does not guarantee a place in a fully booked workshop.</p><details><summary>What counts as a household reader?</summary><p>In this fictional policy, a household reader is a named person registered at the same address. Real services should publish their actual eligibility rules.</p></details><details><summary>Are late fees included?</summary><p>This example does not define late-fee terms. A real comparison should state them clearly before anyone subscribes.</p></details></section></main><footer><p>Created as an HTML comparison-table project.</p></footer>

Styles

body{margin:0;background:#f5f8f6;color:#1c302a;font:16px/1.65 system-ui,sans-serif}main,header,footer{max-width:940px;margin:auto;padding:24px}h1{font-size:clamp(2rem,5vw,3.5rem);line-height:1.12}h2{line-height:1.3}a{color:#12644d;text-underline-offset:3px}button,input,select,textarea{font:inherit}button{cursor:pointer;background:#12644d;color:white;border:0;padding:10px 16px;border-radius:6px}a:focus-visible,button:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible,summary:focus-visible{outline:3px solid #bc6f00;outline-offset:3px}section,article,fieldset{background:white;border:1px solid #d7e5de;padding:20px;border-radius:10px;margin:20px 0}label{display:block;margin-top:12px}input,select,textarea{padding:8px;border:1px solid #73887e;border-radius:4px;max-width:100%;box-sizing:border-box}table{border-collapse:collapse;width:100%}th,td{border:1px solid #c8d7cf;text-align:left;padding:10px}caption{text-align:left;font-weight:700;margin-bottom:10px}nav{display:flex;flex-wrap:wrap;gap:16px}summary{cursor:pointer;font-weight:650;padding:8px}footer{color:#4e665b}.skip{position:absolute;top:-100px}.skip:focus{top:0;background:white;padding:8px;z-index:10}.table-scroll{overflow:auto}table{min-width:620px}thead{background:#edf7f1}th[scope=row]{min-width:180px}
Complete standalone HTML file
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Build an honest product comparison page</title>
<style>body{margin:0;background:#f5f8f6;color:#1c302a;font:16px/1.65 system-ui,sans-serif}main,header,footer{max-width:940px;margin:auto;padding:24px}h1{font-size:clamp(2rem,5vw,3.5rem);line-height:1.12}h2{line-height:1.3}a{color:#12644d;text-underline-offset:3px}button,input,select,textarea{font:inherit}button{cursor:pointer;background:#12644d;color:white;border:0;padding:10px 16px;border-radius:6px}a:focus-visible,button:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible,summary:focus-visible{outline:3px solid #bc6f00;outline-offset:3px}section,article,fieldset{background:white;border:1px solid #d7e5de;padding:20px;border-radius:10px;margin:20px 0}label{display:block;margin-top:12px}input,select,textarea{padding:8px;border:1px solid #73887e;border-radius:4px;max-width:100%;box-sizing:border-box}table{border-collapse:collapse;width:100%}th,td{border:1px solid #c8d7cf;text-align:left;padding:10px}caption{text-align:left;font-weight:700;margin-bottom:10px}nav{display:flex;flex-wrap:wrap;gap:16px}summary{cursor:pointer;font-weight:650;padding:8px}footer{color:#4e665b}.skip{position:absolute;top:-100px}.skip:focus{top:0;background:white;padding:8px;z-index:10}.table-scroll{overflow:auto}table{min-width:620px}thead{background:#edf7f1}th[scope=row]{min-width:180px}</style>
</head>
<body>
<a class="skip" href="#main">Skip to plan comparison</a><header><p><strong>North Library</strong></p><nav aria-label="Page sections"><a href="#plans">Compare plans</a><a href="#terms">Plan details</a></nav></header><main id="main"><h1>Choose a plan for the way you read</h1><p>Compare digital access and borrowing options. These plans and prices are fictional learning examples; no purchase is available.</p><section id="plans" aria-labelledby="plans-title"><h2 id="plans-title">The details, side by side</h2><div class="table-scroll"><table><caption>Fictional membership plan comparison</caption><thead><tr><th scope="col">Feature</th><th scope="col">Digital</th><th scope="col">Standard</th><th scope="col">Family</th></tr></thead><tbody><tr><th scope="row">Monthly price</th><td>₹0</td><td>₹100 per month</td><td>₹180 per month</td></tr><tr><th scope="row">Digital catalogue</th><td>Included</td><td>Included</td><td>Included</td></tr><tr><th scope="row">Physical books at once</th><td>Not included</td><td>4 books</td><td>10 books across the household</td></tr><tr><th scope="row">Workshop bookings</th><td>Public sessions</td><td>Public and member sessions</td><td>Public and member sessions</td></tr><tr><th scope="row">Named readers</th><td>1</td><td>1</td><td>Up to 4</td></tr></tbody></table></div></section><section id="terms" aria-labelledby="terms-title"><h2 id="terms-title">Understand the plan details</h2><p>All physical borrowing remains subject to item availability. A plan does not guarantee a place in a fully booked workshop.</p><details><summary>What counts as a household reader?</summary><p>In this fictional policy, a household reader is a named person registered at the same address. Real services should publish their actual eligibility rules.</p></details><details><summary>Are late fees included?</summary><p>This example does not define late-fee terms. A real comparison should state them clearly before anyone subscribes.</p></details></section></main><footer><p>Created as an HTML comparison-table project.</p></footer>
</body>
</html>

Expected output

Compare three fictional library plans with a semantic table, clear qualifications, and useful native disclosures. The complete file above can be saved as index.html and opened locally. The embedded playground uses the same HTML, CSS, and JavaScript, with additional isolation restrictions.

Acceptance rubric

  • Every price states its billing period and currency.
  • Feature values remain understandable without relying on a checkmark or color.
  • The table has a caption and appropriate row and column headers.
  • Narrow layouts can reveal every column without shrinking text to an unreadable size.
  • FAQ summaries work with keyboard activation.
  • No control claims to complete a purchase or membership request.
  • All limitations that change the comparison are visible near the relevant information.

Common mistakes

Check the relationships in the parsed document rather than judging only the screenshot. Repeated IDs can disconnect labels, a button without an explicit type can submit unexpectedly, and a visual heading may use the wrong semantic level. Test the supplied interaction after changing its structure instead of assuming the JavaScript selectors still find the intended controls.

Accessibility and browser notes

Use Tab and Shift+Tab through the entire interface. Focus must remain visible, and every control must have a useful accessible name. Increase browser zoom and verify that text wraps without hiding actions. Native control appearance varies by browser. A polished screenshot is not evidence that the keyboard workflow or error recovery works; exercise both separately.

Take it further

Add a feature glossary using a description list so readers can understand unfamiliar terms. If the plans change over time, include a verified review date and maintain a source of truth for the values. Avoid updating one promotional card while leaving the comparison table inconsistent.

For an advanced variation, allow the user to hide a plan column. Make the control a real checkbox with a clear label, update both the matching header and cells, and test that the remaining table still has understandable relationships. Do not add that interaction unless it improves the actual comparison task.

Related lessons

Reference standards

WHATWG HTML Living Standard · WAI tutorials