Bootstrap 5 Comparison Table
A comparison table is a structured UI pattern that places two or more options side by side in a tabular layout so users can evaluate features at a glance. It is composed from Bootstrap 5's table utilities (.table, .table-bordered, .table-striped), sticky positioning, badge components, and flex utilities. Bootstrap ships none of this as a named component. Use it whenever a product, pricing, or feature decision benefits from a direct column-by-column contrast.
Bootstrap class
.table, .table-borderedCommon use cases
- A SaaS product page comparing Free, Pro, and Enterprise subscription tiers across a list of feature limits and support levels.
- A hosting provider's documentation page contrasting shared, VPS, and dedicated server specifications such as CPU, RAM, and bandwidth.
- An e-commerce site's buying guide placing three camera models side by side with sensor size, weight, and battery life values.
- A government procurement portal displaying tender responses from multiple suppliers against a fixed set of evaluation criteria.
Variants and classes
| Variant | Description and classes |
|---|---|
| Basic Feature Comparison | A plain bordered table with a sticky first column and tick/cross icons to indicate feature availability per plan.table table-bordered table-hover align-middle |
| Highlighted Column | One column is visually promoted with a background colour and a 'Most Popular' badge pinned to its header to draw attention.table table-bordered table-hover align-middle bg-primary-subtle |
| Striped Responsive Wrapper | Wrapped in a div with overflow-x-auto and table-striped so the table scrolls horizontally on small screens without breaking the layout.table-responsive + table table-bordered table-striped |
| Card-based Column Layout | Instead of a traditional table element, Bootstrap card and grid columns simulate a comparison layout for fully custom styling per plan.card h-100 border-2 shadow-sm |
Code example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Pricing Comparison Table</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css">
<style>
.comparison-table th:first-child,
.comparison-table td:first-child {
position: sticky;
left: 0;
background-color: var(--bs-body-bg);
z-index: 1;
border-right: 2px solid var(--bs-border-color);
font-weight: 600;
}
.comparison-table thead th.col-highlight {
background-color: var(--bs-primary);
color: #fff;
}
.comparison-table tbody td.col-highlight {
background-color: var(--bs-primary-bg-subtle);
}
.tick { color: #198754; font-size: 1.15rem; }
.cross { color: #dc3545; font-size: 1.15rem; }
</style>
</head>
<body class="py-5">
<div class="container">
<h2 class="mb-1 fw-bold text-center">Choose Your Plan</h2>
<p class="text-center text-muted mb-4">All plans include a 14-day free trial. No credit card required.</p>
<div class="table-responsive">
<table class="table table-bordered table-hover align-middle comparison-table">
<thead class="table-dark">
<tr>
<th scope="col" style="min-width:200px">Feature</th>
<th scope="col" class="text-center" style="min-width:140px">Free</th>
<th scope="col" class="text-center col-highlight" style="min-width:140px">
Pro
<span class="badge bg-warning text-dark ms-1">Popular</span>
</th>
<th scope="col" class="text-center" style="min-width:140px">Enterprise</th>
</tr>
</thead>
<tbody>
<tr>
<td>Monthly price</td>
<td class="text-center">£0</td>
<td class="text-center col-highlight fw-semibold">£19</td>
<td class="text-center">£79</td>
</tr>
<tr>
<td>Team members</td>
<td class="text-center">1</td>
<td class="text-center col-highlight">Up to 10</td>
<td class="text-center">Unlimited</td>
</tr>
<tr>
<td>Storage</td>
<td class="text-center">5 GB</td>
<td class="text-center col-highlight">50 GB</td>
<td class="text-center">1 TB</td>
</tr>
<tr>
<td>Custom domain</td>
<td class="text-center"><span class="cross" aria-label="Not included">✗</span></td>
<td class="text-center col-highlight"><span class="tick" aria-label="Included">✓</span></td>
<td class="text-center"><span class="tick" aria-label="Included">✓</span></td>
</tr>
<tr>
<td>Priority support</td>
<td class="text-center"><span class="cross" aria-label="Not included">✗</span></td>
<td class="text-center col-highlight"><span class="tick" aria-label="Included">✓</span></td>
<td class="text-center"><span class="tick" aria-label="Included">✓</span></td>
</tr>
<tr>
<td>SSO & SAML</td>
<td class="text-center"><span class="cross" aria-label="Not included">✗</span></td>
<td class="text-center col-highlight"><span class="cross" aria-label="Not included">✗</span></td>
<td class="text-center"><span class="tick" aria-label="Included">✓</span></td>
</tr>
<tr>
<td>SLA uptime guarantee</td>
<td class="text-center">99.5%</td>
<td class="text-center col-highlight">99.9%</td>
<td class="text-center">99.99%</td>
</tr>
</tbody>
<tfoot>
<tr>
<td></td>
<td class="text-center"><a href="#" class="btn btn-outline-secondary btn-sm">Get started</a></td>
<td class="text-center col-highlight"><a href="#" class="btn btn-primary btn-sm">Start free trial</a></td>
<td class="text-center"><a href="#" class="btn btn-outline-dark btn-sm">Contact sales</a></td>
</tr>
</tfoot>
</table>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>Live examples
Simple Two-Column Feature List
A minimal table comparing two product editions with text values. No sticky column required because there are few columns and the table fits on most screens.
Card-based Plan Comparison
Uses Bootstrap grid and card components instead of a table element, giving full control over per-column styling and making each plan a distinct card on desktop.
Striped Scrollable Specification Table
A horizontally scrollable, striped table suited to comparing technical specifications such as hardware components where many narrow columns are needed.
Canvas template variants
Canvas Builder builds pages on the Canvas HTML template, which adds its own styled versions of Bootstrap 5 components. Variants you can ask for in a prompt:
- Pricing comparison table with highlighted 'Most Popular' column, generated automatically by Canvas Builder from a pricing prompt
- Three-tier SaaS feature matrix with tick and cross icons
- Card-based plan comparison with per-column CTA buttons
- Scrollable hardware specification table with sticky feature column
- Dark-header comparison table with badge labels on premium tiers
Best practices
Sticky first column on wide tables
Apply position: sticky; left: 0 to the first th and td in each row using a shared class, and set a solid background colour matching the page so cells do not bleed through when the table scrolls horizontally. Always add z-index: 1 to prevent the sticky cell from rendering beneath other cells.
Accessibility for tick and cross icons
Avoid relying solely on colour or decorative characters to convey availability. Add aria-label="Included" or aria-label="Not included" to each icon element so screen readers can interpret the value correctly. Consider supplementing icons with visually hidden text via Bootstrap's .visually-hidden class for maximum compatibility.
Highlighting a recommended column
Use Bootstrap's contextual colour utilities such as bg-primary-subtle on tbody cells and bg-primary on the thead cell to highlight a recommended plan. Pair this with a .badge inside the header cell to reinforce the recommendation visually without altering the table's semantic structure.
Responsive behaviour at small breakpoints
Wrap the table in a div with the .table-responsive class to enable horizontal scrolling on viewports narrower than the table's natural width. For card-based layouts, switch to Bootstrap's grid (col-12 col-md-4) so each plan stacks vertically on mobile and expands to side-by-side columns on medium and larger screens.