ComparisonTable
MD · 1950B gzip budgetSide-by-side feature comparison with highlighted differences.
- Category
- Data display
- Budget
- md, several states or a live subscription
- External runtime
- React / React DOM only
axe fixtureSSR rendersource scanbundle budget
Preview
Live fixture| Feature | Pro | Free |
|---|---|---|
| Feature A |
Try the component here. Locale-aware formatting and direction follow the selected language; example content and labels are not automatically translated. Overlay demos use interactive launchers.
Install
npx shadcn@latest add https://gear5-ui.vercel.app/r/comparison-table.jsonCopies the source into your project. Pulls in 1 shared registry item: cn.
New here? Set up Tailwind and import aliases first →Source & props
Edit on GitHub ↗Prop types and inline documentation are included below. This is repository source; the installer rewrites shared imports for your project.
import { cn } from "../lib/cn";
export interface ComparisonFeature {
name: string;
values: (string | boolean)[];
}
export interface ComparisonTableProps {
plans: string[];
features: ComparisonFeature[];
className?: string;
}
/**
* Side-by-side feature comparison table. Each plan column is a `<th>` with
* `scope="col"`. The table uses `aria-label` for the comparison title.
*/
export function ComparisonTable({ plans, features, className }: ComparisonTableProps) {
return (
<div className={cn("overflow-x-auto text-start", className)}>
<table className="w-full border-collapse text-sm" role="table" aria-label="Feature comparison">
<thead>
<tr className="border-b border-neutral-200 dark:border-neutral-800">
<th scope="col" className="p-3 text-start font-medium text-neutral-600 dark:text-neutral-400">
Feature
</th>
{plans.map((plan) => (
<th
key={plan}
scope="col"
className="p-3 text-center font-semibold text-neutral-900 dark:text-neutral-100"
>
{plan}
</th>
))}
</tr>
</thead>
<tbody>
{features.map((feature) => (
<tr key={feature.name} className="border-b border-neutral-100 dark:border-neutral-900">
<th scope="row" className="p-3 text-start font-medium text-neutral-700 dark:text-neutral-300">
{feature.name}
</th>
{feature.values.map((value, index) => (
<td key={index} className="p-3 text-center">
{typeof value === "boolean" ? (
<span role="img" aria-label={value ? "Included" : "Not included"}>
<span aria-hidden="true" className={value ? "text-green-600 dark:text-green-400" : "text-neutral-300 dark:text-neutral-600"}>
{value ? "✓" : "—"}
</span>
</span>
) : (
<span className="text-neutral-700 dark:text-neutral-300">{value}</span>
)}
</td>
))}
</tr>
))}
</tbody>
</table>
</div>
);
}
What CI checks
Quality contract- Bundled, minified and gzipped against its tier budget
- Audited by axe in the state previewed above
- Rendered through react-dom/server with no browser globals
- Scanned for network calls, dangerous sinks, and unguarded animation