Skip to main content

Comparison Table

3 min readStableIntermediate

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.

FeatureStarterTeam
Custom domainIncludedIncludedIncludedIncluded
Private access modeNot availableNot availableIncludedIncluded
content/features/components/comparison-table.mdx
MDX
<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

FeatureStarterRecommendedTeamEnterprise
Custom domainIncludedIncludedIncludedIncludedIncludedIncluded
Private access modeNot availableNot availableIncludedIncludedIncludedIncluded
Audit logNot availableNot availablePartialPartialIncludedIncluded
content/features/components/comparison-table.mdx
MDX
<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

CapabilityStarterTeamRecommendedEnterprise
Custom domainIncludedIncludedIncludedIncludedIncludedIncluded
Private access modeNot availableNot availableIncludedIncludedIncludedIncluded
Audit logPartialPartialPartialPartialIncludedIncluded
Data residencyInfoInfoInfoInfoIncludedIncluded
Priority supportNot availableNot availablePremiumPremiumIncludedIncluded
SAML SSOEnterpriseEnterpriseEnterpriseEnterpriseIncludedIncluded
Extra editor seatsAdd-onAdd-onAdd-onAdd-onIncludedIncluded
Scheduled publishingComing soonComing soonComing soonComing soonComing soonComing soon
AI answersNewNewNewNewNewNew
Build concurrencyUpgradeUpgradeIncludedIncludedIncludedIncluded
PriceFreePer seatContact sales
content/features/components/comparison-table.mdx
MDX
<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.

RuntimeNode 20Node 24
SupportedIncludedIncludedIncludedIncluded
Recommended for new projectsNot availableNot availableIncludedIncluded
content/features/components/comparison-table.mdx
MDX
<ComparisonTable
  headers={['Runtime', 'Node 20', 'Node 24']}
  rows={[
    { feature: 'Supported', values: ['check', 'check'] },
    { feature: 'Recommended for new projects', values: ['cross', 'check'] },
  ]}
/>

Options

titlestring

Heading text in a bar above the table. Leave it off and the table starts at the header row.

headersJSON string | string[]required

Column 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[]required

Row 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.

highlightnumber

Index 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 value

Teal check mark. Tooltip: Included.

crosscell value

Red X. Tooltip: Not available.

partialcell value

Amber minus. Tooltip: Partial.

infocell value

Sky-blue info circle. Tooltip: Info.

starcell value

Purple star. Tooltip: Premium.

clockcell value

Gray clock. Tooltip: Coming soon.

pluscell value

Teal plus. Tooltip: Add-on.

lockcell value

Gray padlock. Tooltip: Enterprise.

sparklecell value

Violet sparkles. Tooltip: New.

zapcell value

Amber lightning bolt. Tooltip: Upgrade.

any other stringcell value

Rendered as plain secondary text, with no icon and no tooltip.

Was this page helpful?

© 2026 DevOps. All rights reserved.