Three-Tier Pricing
The canonical Starter / Pro / Enterprise grid, with the middle tier promoted.
6 个框架初级
A real table comparing every feature across plans, with accessible tick cells.
<!--
This is a real <table>, and it has to be. A grid of divs looks identical and
loses the only thing that makes the data navigable without sight: with
scope="col" on the plans and scope="row" on the features, a screen reader
announces "Pro, Priority support, Included" when the user lands on a cell. Take
the table away and that cell announces "Included" - true, but about what?
Two rules the ticks depend on:
1. The svg is aria-hidden and every boolean cell carries real text next to it.
An icon alone conveys nothing, and title/aria-label on an <svg> is read
inconsistently across screen readers.
2. ✓ and ✗ differ in shape, not just colour, so the answer survives being
printed in greyscale or read by someone who cannot separate red from green.
The scroll container is focusable (tabindex="0") with a role and a name: a
region that scrolls but cannot be focused is unreachable for anyone driving
the page from the keyboard alone.
-->
<div class="matrix__scroll" role="region" aria-labelledby="matrix-caption" tabindex="0">
<table class="matrix">
<caption class="matrix__caption" id="matrix-caption">Compare plans</caption>
<thead>
<tr>
<th class="matrix__corner" scope="col">Feature</th>
<th class="matrix__plan" scope="col">
Starter
<span class="matrix__plan-price">$0/month</span>
</th>
<th class="matrix__plan matrix__plan--highlighted" scope="col">
Pro
<span class="matrix__plan-price">$19/month</span>
</th>
<th class="matrix__plan" scope="col">
Enterprise
<span class="matrix__plan-price">$49/month</span>
</th>
</tr>
</thead>
<tbody>
<tr>
<th class="matrix__row" scope="row">Projects</th>
<td class="matrix__cell">3</td>
<td class="matrix__cell">Unlimited</td>
<td class="matrix__cell">Unlimited</td>
</tr>
<tr>
<th class="matrix__row" scope="row">Storage</th>
<td class="matrix__cell">1 GB</td>
<td class="matrix__cell">100 GB</td>
<td class="matrix__cell">Unlimited</td>
</tr>
<tr>
<th class="matrix__row" scope="row">Priority support</th>
<td class="matrix__cell">
<svg class="matrix__icon matrix__icon--no" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path d="M6.3 6.3a1 1 0 0 1 1.4 0L10 8.6l2.3-2.3a1 1 0 1 1 1.4 1.4L11.4 10l2.3 2.3a1 1 0 0 1-1.4 1.4L10 11.4l-2.3 2.3a1 1 0 0 1-1.4-1.4L8.6 10 6.3 7.7a1 1 0 0 1 0-1.4Z" />
</svg>
<span class="matrix__sr">Not included</span>
</td>
<td class="matrix__cell">
<svg class="matrix__icon matrix__icon--yes" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path d="M16.7 5.3a1 1 0 0 1 0 1.4l-7.5 7.5a1 1 0 0 1-1.4 0L3.3 9.7a1 1 0 1 1 1.4-1.4l3.8 3.8 6.8-6.8a1 1 0 0 1 1.4 0Z" />
</svg>
<span class="matrix__sr">Included</span>
</td>
<td class="matrix__cell">
<svg class="matrix__icon matrix__icon--yes" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path d="M16.7 5.3a1 1 0 0 1 0 1.4l-7.5 7.5a1 1 0 0 1-1.4 0L3.3 9.7a1 1 0 1 1 1.4-1.4l3.8 3.8 6.8-6.8a1 1 0 0 1 1.4 0Z" />
</svg>
<span class="matrix__sr">Included</span>
</td>
</tr>
<tr>
<th class="matrix__row" scope="row">SSO and SCIM</th>
<td class="matrix__cell">
<svg class="matrix__icon matrix__icon--no" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path d="M6.3 6.3a1 1 0 0 1 1.4 0L10 8.6l2.3-2.3a1 1 0 1 1 1.4 1.4L11.4 10l2.3 2.3a1 1 0 0 1-1.4 1.4L10 11.4l-2.3 2.3a1 1 0 0 1-1.4-1.4L8.6 10 6.3 7.7a1 1 0 0 1 0-1.4Z" />
</svg>
<span class="matrix__sr">Not included</span>
</td>
<td class="matrix__cell">
<svg class="matrix__icon matrix__icon--no" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path d="M6.3 6.3a1 1 0 0 1 1.4 0L10 8.6l2.3-2.3a1 1 0 1 1 1.4 1.4L11.4 10l2.3 2.3a1 1 0 0 1-1.4 1.4L10 11.4l-2.3 2.3a1 1 0 0 1-1.4-1.4L8.6 10 6.3 7.7a1 1 0 0 1 0-1.4Z" />
</svg>
<span class="matrix__sr">Not included</span>
</td>
<td class="matrix__cell">
<svg class="matrix__icon matrix__icon--yes" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path d="M16.7 5.3a1 1 0 0 1 0 1.4l-7.5 7.5a1 1 0 0 1-1.4 0L3.3 9.7a1 1 0 1 1 1.4-1.4l3.8 3.8 6.8-6.8a1 1 0 0 1 1.4 0Z" />
</svg>
<span class="matrix__sr">Included</span>
</td>
</tr>
<tr>
<th class="matrix__row" scope="row">Uptime SLA</th>
<td class="matrix__cell">
<svg class="matrix__icon matrix__icon--no" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path d="M6.3 6.3a1 1 0 0 1 1.4 0L10 8.6l2.3-2.3a1 1 0 1 1 1.4 1.4L11.4 10l2.3 2.3a1 1 0 0 1-1.4 1.4L10 11.4l-2.3 2.3a1 1 0 0 1-1.4-1.4L8.6 10 6.3 7.7a1 1 0 0 1 0-1.4Z" />
</svg>
<span class="matrix__sr">Not included</span>
</td>
<td class="matrix__cell">99.5%</td>
<td class="matrix__cell">99.9%</td>
</tr>
</tbody>
</table>
</div>| Prop | 类型 | 默认值 | 说明 |
|---|---|---|---|
className | string | - | 合并到根元素上的额外类名。 |
This is a real `<table>`, and it has to be. A grid of divs looks identical and throws away the only thing that makes the data navigable without sight: with `scope="col"` on the plans and `scope="row"` on the features, a screen reader announces "Pro, Priority support, Included" when the user lands on a cell - remove the table and that cell announces "Included", which is true but about nothing. The tick cells follow two rules. The `<svg>` is `aria-hidden` and every boolean carries real `sr-only` text beside it, because an icon alone conveys nothing and `title` on an SVG is read inconsistently; and ✓ and ✗ differ in shape rather than only colour, so the answer survives greyscale printing and colour-blind readers. The scroll wrapper is focusable with a name - a region that scrolls but cannot be focused is unreachable from the keyboard - and the wrapper scrolls, not the table, since a table cannot form a scroll container itself. That is the usual reason a comparison table clips its last plan on a phone. Cells are typed `string | boolean`, so one column can mix "99.5%" with a tick and the render is forced to branch rather than printing the string "false".