Skip to content
Component installs need the registry setup— the Base UI shadcn project, the @vegastack namespace and the Cloudflare Access service token.
VegaStack Design

Comparison Matrix

A plan-feature matrix with accessible availability cells and a highlighted plan column.

Status
stable
Since
0.3.0
Accessibility pattern
native table semantics

Last updated

FreePlusPro
Enrichment
Company dataIncludedIncludedIncluded
Contact enrichmentNot includedIncludedIncluded
Call intelligenceNot includedNot includedIncluded
Workspace
Seats310Unlimited
Permission controlsNot includedIncludedIncluded

Install

Add Comparison Matrix from the VegaStack registry. The CLI verifies the item's integrity hash before writing it.

pnpm dlx shadcn@latest add @vegastack/comparison-matrix

The same command installs the registry items it composes: @vegastack/use-overflow.

Usage

import {
  ComparisonGroup,
  ComparisonMatrix,
  ComparisonRow,
} from "@/components/ui/comparison-matrix";

<ComparisonMatrix plans={["Free", "Pro"]} highlightedIndex={1}>
  <ComparisonGroup>Enrichment</ComparisonGroup>
  <ComparisonRow feature="Company data" availability={[true, true]} />
  <ComparisonRow feature="Seats" availability={["3", "Unlimited"]} />
</ComparisonMatrix>;

Anatomy

Comparison Matrix is a compound component. Every exported part, with the data-slot it renders (generated from the canonical source):

ComparisonGroup — data-slot="comparison-group"
ComparisonMatrix — data-slot="comparison-matrix" | "comparison-matrix-container"
ComparisonRow — data-slot="comparison-row"

Examples

The highlighted plan uses a subtle column surface rather than elevation. Boolean availability pairs a visible glyph with screen-reader copy; literal limits render as authored.

At narrow widths the matrix keeps readable columns and scrolls horizontally. The feature column is sticky, the scroll region is labelled and becomes keyboard-focusable exactly while it can scroll, and edge fades indicate that more plans are available off-screen.

FreePlusPro
Enrichment
Company dataIncludedIncludedIncluded
Contact enrichmentNot includedIncludedIncluded
Call intelligenceNot includedNot includedIncluded
Workspace
Seats310Unlimited
Permission controlsNot includedIncludedIncluded

Unknown cells and no promoted plan

highlightedIndex is optional — omit it and no column is promoted. When a row's availability array is shorter than plans, the matrix holds every column open and marks the missing cells "Not specified" (overridable per row with unknownLabel) rather than shifting the row left or silently reading as "not included". An unsupplied value is not a negative claim.

StarterTeamEnterprise
Support
Email supportIncludedIncludedIncluded
Response time48h8hNot specified
Named contactNot includedNot specifiedNot specified

API Reference

ComparisonMatrix

PropTypeDefaultDescription
plans*React.ReactNode[]Plan names, in column order.
highlightedIndexnumberIndex into plans to tint as the promoted column.
planActionsReact.ReactNode[]Optional per-plan header extras (CTAs), aligned under the names.
scrollLabelstring'Plan comparison table'Accessible label for the horizontally scrollable region.

Data attributes and CSS variables on ComparisonMatrix

AttributeValues
data-highlighted""
data-scrollable""
data-slot"comparison-matrix" | "comparison-matrix-container"

ComparisonGroup

ComparisonGroup passes native <tr> props and a forwarded ref to its group row.

ComparisonRow

PropTypeDefaultDescription
availability*React.ReactNode[]One entry per plan: true (included → ✓), false (not included → −), or any node for a literal value ("3 seats").
feature*React.ReactNodeThe feature name (the row header).
includedLabelstring'Included'Screen-reader copy for included boolean cells.
notIncludedLabelstring'Not included'Screen-reader copy for unavailable boolean cells.
unknownLabelstring'Not specified'Screen-reader copy for a cell with no supplied value (fewer availability entries than plans).

Data attributes and CSS variables on ComparisonRow

AttributeValues
data-slot"comparison-row"

Accessibility

Native table semantics: plans are columnheaders, features are rowheaders, groups span the table. Boolean availability renders ✓/− glyphs WITH sr-only text ("Included"/"Not included") — never bare dots. Literal values ("3 seats") render as-is. The enclosing region uses scrollLabel ("Plan comparison table" by default) as its accessible name.

KeyAction
TabMove through interactive plan actions in source order.
Shift + mouse wheelScroll horizontally where the platform supports it.
Enter / SpaceActivate the focused plan action.
ContractStates tested
Behaviourdefault, success, scrollable
Accessibilitysemantic-html
Visualdefault, success

Do / Don't

Do
Use row and column headers, pair boolean glyphs with text alternatives, and keep plan order consistent across breakpoints.
Don't
Communicate availability by color alone or use a comparison table for unrelated marketing copy.

On this page