Heading text in a bar above the table. Leave it off and the table starts at the header row.
Comparison Table
ComparisonTable lays out a feature matrix: one row per feature, one column per
option, and a small icon in each cell instead of a wall of yes/no text. Ten cell
values render as an icon with a hover tooltip — check, cross, partial,
info, star, clock, plus, lock, sparkle, and zap — and any other
string renders as plain text. Each example below shows the live component first,
then the exact MDX that produced it.
Quick Start
Two required props: headers and rows, both passed as JSON array strings.
| Feature | Starter | Team |
|---|---|---|
| Custom domain | Included | Included |
| Private access mode | Not available | Included |
<ComparisonTable
headers='["Feature", "Starter", "Team"]'
rows='[
{ "feature": "Custom domain", "values": ["check", "check"] },
{ "feature": "Private access mode", "values": ["cross", "check"] }
]'
/>Adding Options
title puts a heading bar above the table, and highlight tints one column and
prints a Recommended label above its header.
Plan comparison
| Feature | Starter | RecommendedTeam | Enterprise |
|---|---|---|---|
| Custom domain | Included | Included | Included |
| Private access mode | Not available | Included | Included |
| Audit log | Not available | Partial | Included |
<ComparisonTable
title="Plan comparison"
headers='["Feature", "Starter", "Team", "Enterprise"]'
highlight={2}
rows='[
{ "feature": "Custom domain", "values": ["check", "check", "check"] },
{ "feature": "Private access mode", "values": ["cross", "check", "check"] },
{ "feature": "Audit log", "values": ["cross", "partial", "check"] }
]'
/>Advanced
Hover any icon below to read its label; the last row shows a value that matches no indicator key, so it falls through to plain text.
Every indicator key
| Capability | Starter | Team | RecommendedEnterprise |
|---|---|---|---|
| Custom domain | Included | Included | Included |
| Private access mode | Not available | Included | Included |
| Audit log | Partial | Partial | Included |
| Data residency | Info | Info | Included |
| Priority support | Not available | Premium | Included |
| SAML SSO | Enterprise | Enterprise | Included |
| Extra editor seats | Add-on | Add-on | Included |
| Scheduled publishing | Coming soon | Coming soon | Coming soon |
| AI answers | New | New | New |
| Build concurrency | Upgrade | Included | Included |
| Price | Free | Per seat | Contact sales |
<ComparisonTable
title="Every indicator key"
headers='["Capability", "Starter", "Team", "Enterprise"]'
highlight={3}
rows='[
{ "feature": "Custom domain", "values": ["check", "check", "check"] },
{ "feature": "Private access mode", "values": ["cross", "check", "check"] },
{ "feature": "Audit log", "values": ["partial", "partial", "check"] },
{ "feature": "Data residency", "values": ["info", "info", "check"] },
{ "feature": "Priority support", "values": ["cross", "star", "check"] },
{ "feature": "SAML SSO", "values": ["lock", "lock", "check"] },
{ "feature": "Extra editor seats", "values": ["plus", "plus", "check"] },
{ "feature": "Scheduled publishing", "values": ["clock", "clock", "clock"] },
{ "feature": "AI answers", "values": ["sparkle", "sparkle", "sparkle"] },
{ "feature": "Build concurrency", "values": ["zap", "check", "check"] },
{ "feature": "Price", "values": ["Free", "Per seat", "Contact sales"] }
]'
/>headers and rows also accept real JavaScript arrays through a JSX
expression. That form skips JSON escaping and reads better once the row list
grows past a few entries.
| Runtime | Node 20 | Node 24 |
|---|---|---|
| Supported | Included | Included |
| Recommended for new projects | Not available | Included |
<ComparisonTable
headers={['Runtime', 'Node 20', 'Node 24']}
rows={[
{ feature: 'Supported', values: ['check', 'check'] },
{ feature: 'Recommended for new projects', values: ['cross', 'check'] },
]}
/>Options
titlestringheadersJSON string | string[]requiredColumn labels, as a JSON array string or a real array. The first entry labels the feature column; the rest are the columns being compared. The component renders nothing when this list is empty or the JSON fails to parse.
rowsJSON string | RowData[]requiredRow objects, each with a feature label and a values array. Accepts a JSON
array string or a real array, and renders nothing when the list is empty or
the JSON fails to parse. Each entry in values becomes one cell, so keep the
array one shorter than headers; a short array leaves the trailing columns
blank and a long one pushes cells past the last header.
highlightnumberIndex into headers of the column to tint. headers[0] is the feature
column, so highlight={1} marks the first compared column and adds the
Recommended label above it. Passing 0 tints the feature column without the
label; an index past the last header tints nothing.
Cell values
Ten keywords render as a colored icon with a tooltip on hover. Matching is exact
and lowercase — Check is not check, so it falls through to the plain text
branch. Anything that is not one of these ten renders as plain secondary text,
which is how you write a price, a quota, or a version number into a cell.
checkcell valueTeal check mark. Tooltip: Included.
crosscell valueRed X. Tooltip: Not available.
partialcell valueAmber minus. Tooltip: Partial.
infocell valueSky-blue info circle. Tooltip: Info.
starcell valuePurple star. Tooltip: Premium.
clockcell valueGray clock. Tooltip: Coming soon.
pluscell valueTeal plus. Tooltip: Add-on.
lockcell valueGray padlock. Tooltip: Enterprise.
sparklecell valueViolet sparkles. Tooltip: New.
zapcell valueAmber lightning bolt. Tooltip: Upgrade.
any other stringcell valueRendered as plain secondary text, with no icon and no tooltip.