
Challenge · hard
Accessible HTML Pricing Table: thead, tbody, tfoot
Goal: Rebuild an old, flat price table as a properly structured plan comparison.
Learn
A pricing table compares plans side by side. That is tabular data, so a table is the right tool here. A finished one has four parts: a <caption>, a <thead> holding the column headers, a <tbody> with a row per feature, and a <tfoot> for the summary row. In this table the summary row is the set of buttons for choosing a plan. The tfoot section of the HTML standard (opens in a new tab) covers that use.
Plan names become <th scope="col"> and feature names <th scope="row">. A screen reader then reads every price with both its plan and its feature, as WCAG 2.2 success criterion 1.3.1 (opens in a new tab) asks. Cells that repeat the same thing can merge with colspan. Put each price in <data value="9"> so software gets a plain number, and spell out units with <abbr title="...">.
The border attribute is obsolete. Borders come from CSS in a style block; the style element lesson shows how. Need a refresher on headers? Read table headers and captions.
The short version
- A full table splits into
<thead>,<tbody>and<tfoot>. - Mark plans with
scope="col"and features withscope="row". Every price then has two headers. <data value>gives each price a number software can read;<abbr title>spells out the units.- Drop the obsolete
borderattribute and the bold cells. Use CSS and real header cells.
Example
<table>
<caption>Coffee sizes</caption>
<thead>
<tr>
<td></td>
<th scope="col">Small</th>
<th scope="col">Large</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Price</th>
<td><data value="2">$2</data></td>
<td><data value="3">$3</data></td>
</tr>
</tbody>
</table>Your task
Eight changes turn this into a proper pricing table:
- Delete the
borderattribute and every<b>tag. (You can add borders back from a<style>block.) - Give the table a
<caption>. - Move the row of plan names into a
<thead>and make them<th scope="col">cells (3). - Place the 4 feature rows in a
<tbody>, with each feature name as a<th scope="row">. - Wrap each of the 3 prices in
<data>with a numericvalue. - Mark GB or TB with
<abbr>and atitle. - Replace the three 'Email' support cells with a single
colspan="3"cell that says it once, more plainly. - Move the row of 'Choose' links into a
<tfoot>.
Ctrl+Enter checks your code. Try Visual edit to change the page directly, DOM tree to see how the browser reads it, and Outline to hear it like a screen reader.
Quick quiz
Frequently asked questions
How do I make a pricing table in HTML?
Start with a real <table> and a <caption>. The plan names go in a <thead> row of <th scope="col"> cells. Each feature gets a row in the <tbody> that begins with <th scope="row">, and the sign-up links go in a <tfoot>. Borders, colors and a highlighted plan are CSS. Some designs use stacked cards; a table-to-div converter (opens in a new tab) lets you put that div layout next to the table. For real comparison data, though, the table is the accessible one.
What is the HTML data element used for?
It gives readable text a machine-readable twin. <data> shows people the text and keeps a clean value in its value attribute, as in <data value="9">$9</data>. A script can then sort or compare plans by that number with no need to strip currency symbols, which is the purpose given in the data element definition (opens in a new tab). Dates and times use <time datetime> instead.