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. Any other string
renders as plain text.
Quick Start
Two required props: headers and rows, both passed as JSON array strings.
| Feature | Starter | Team |
|---|---|---|
| Custom domain | IncludedIncluded | IncludedIncluded |
| Private access mode | Not availableNot available | IncludedIncluded |
<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 | IncludedIncluded | IncludedIncluded | IncludedIncluded |
| Private access mode | Not availableNot available | IncludedIncluded | IncludedIncluded |
| Audit log | Not availableNot available | PartialPartial | IncludedIncluded |
<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 | IncludedIncluded | IncludedIncluded | IncludedIncluded |
| Private access mode | Not availableNot available | IncludedIncluded | IncludedIncluded |
| Audit log | PartialPartial | PartialPartial | IncludedIncluded |
| Data residency | InfoInfo | InfoInfo | IncludedIncluded |
| Priority support | Not availableNot available | PremiumPremium | IncludedIncluded |
| SAML SSO | EnterpriseEnterprise | EnterpriseEnterprise | IncludedIncluded |
| Extra editor seats | Add-onAdd-on | Add-onAdd-on | IncludedIncluded |
| Scheduled publishing | Coming soonComing soon | Coming soonComing soon | Coming soonComing soon |
| AI answers | NewNew | NewNew | NewNew |
| Build concurrency | UpgradeUpgrade | IncludedIncluded | IncludedIncluded |
| 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 | IncludedIncluded | IncludedIncluded |
| Recommended for new projects | Not availableNot available | IncludedIncluded |
<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
Matching is exact and lowercase. Check is not check, so it falls through to
the plain text branch. Anything outside these ten renders as plain secondary
text, which is where a price, a quota, or a version number goes.
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.