Components
Comparison Table
BetaSide-by-side feature comparison for holiday packages, room types, or board basis options. Tick/cross cells and a highlighted recommended column guide decision-making.
| Feature | Self Catering | Half Board | All InclusiveRecommended |
|---|---|---|---|
| Breakfast | |||
| Dinner | |||
| Drinks included | |||
| Snacks all day | |||
| Airport transfers |
Purpose
The ComparisonTable is a structured grid that places multiple options side-by-side so customers can evaluate feature differences at a glance. It is most useful when:
- Board basis comparison — Self Catering vs Half Board vs All Inclusive
- Room type comparison — Standard Room vs Garden Villa vs Overwater Bungalow
- Holiday package tiers — Essential vs Premium vs Luxury
- Destination feature comparison — comparing what's included at two resorts
A highlighted column (with a "Recommended" chip) draws attention to the option Kuoni specialists suggest. A sticky first column keeps feature labels visible when the table scrolls horizontally on small screens.
Usage
Reach for ComparisonTable when a customer must weigh two or more named options against the same set of features — board basis, room type, or package tier. When you only need to list what one single option includes (with no side-by-side comparison), use FeatureList instead; it is lighter weight and doesn't force a grid.
ComparisonTable typically sits on product detail pages below the hero, in quote summaries where specialists present alternatives, or inside a modal/drawer triggered by a "Compare" action from a listing page.
Anatomy
| Feature | Standard | PremiumRecommended |
|---|---|---|
| Airport transfers | ||
| Meals | Breakfast | All meals |
| Spa access |
- 1Header row — Column labels in a grey-50 header row. Highlighted column shows in teal-50 with a "Recommended" chip.
- 2Feature column (sticky) — Leftmost column with feature names. Stays visible on horizontal scroll via sticky positioning.
- 3Included cell (tick) — Green Check icon (text-success) with aria-label="Included".
- 4Excluded cell (cross) — Grey X icon (text-grey-300) with aria-label="Not included".
- 5N/A cell (dash) — Grey dash for features that are not applicable to the option.
- 6Text cell — String values are rendered as plain text in kuoni-dark. Used for prices, quantities, or partial inclusions.
- 7Feature note — Optional secondary note below the feature name in grey-400. e.g. "(subject to availability)".
Variants
Boolean tick/cross (most common)
Set cell values to true (green tick), false (grey cross), or null (grey dash).
| Feature | Standard Room | Deluxe Room | Villa SuiteRecommended |
|---|---|---|---|
| Sea view | |||
| Private pool | |||
| Butler service | |||
| Outdoor shower | |||
| King bed |
Mixed content (text + boolean)
String values render as text cells. Use for quantities, grade descriptions, or partial inclusions.
| Feature | Essential | LuxuryRecommended |
|---|---|---|
| Nights | 7 | 10 |
| Star rating | 4★ | 5★ |
| Board basis | Bed and Breakfast | All Inclusive |
| Airport transfers | ||
| Excursions | 2 included |
With feature notes
Add a note to any row for secondary context under the feature name.
| Feature | Half Board | Full BoardRecommended |
|---|---|---|
| Dinner Included each evening | ||
| Lunch Subject to availability | ||
| Afternoon tea |
Best practices
Highlight one column as recommended when there is a clear best-value or most-popular option.
'All Inclusive' highlighted with a Recommended chip draws the eye to the best value option.
Highlight more than one column in the same table.
Two highlighted columns compete for attention — neither stands out.
Order rows from most important to least important for the typical customer.
Rows in order of perceived importance let users scan the most important features first.
Order rows alphabetically by feature name.
Alphabetical order puts minor amenities above key inclusions like meals and transfers.
Use string cell values for nuanced inclusions that a simple tick or cross would misrepresent.
Use text values like 'Bed and Breakfast' or '7 nights' for features that are not simply included or excluded.
Use a tick for features that have partial or variable inclusion without clarifying text.
A tick for 'Meals' could mean breakfast-only or all-inclusive — text clarifies.
Always provide a caption prop describing what the table is comparing.
The caption prop is read by screen readers as the table's accessible name.
Omit the caption on comparison tables.
An anonymous table gives screen reader users no context for what is being compared.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| columns* | Array<{ label: string; value: string; highlighted?: boolean }> | — | Column definitions. value is used as the key in each row's values object. highlighted=true marks the recommended column in teal. |
| rows* | Array<{ feature: string; note?: string; values: Record<string, boolean | string | null> }> | — | Row definitions. values is a map of column.value to cell content. true=tick, false=cross, null=dash, string=text. |
| highlightColumn | string | — | Alternative to column.highlighted — pass the column value to highlight it programmatically. |
| caption | string | — | Screen-reader-only table caption. Describes what is being compared. |
| stickyFirstColumn | boolean | true | Makes the feature name column sticky on horizontal scroll. |
| className | string | — | Additional Tailwind classes on the scroll wrapper. |
Accessibility
Table semantics
ComparisonTable renders a proper <table> with <thead>, <tbody>, <th scope="col"> headers, and <td> cells. This gives screen reader users full table navigation (read row, read column header, navigate by cell).
Cell icons
Tick, cross, and dash icons each have aria-label:
- Tick:
aria-label="Included" - Cross:
aria-label="Not included" - Dash:
aria-label="Not applicable"
The icons themselves are aria-hidden="true" so only the aria-label is announced.
Screen reader navigation
Screen reader users can navigate with:
- Arrow keys → move between cells
- Read table → announces cell value + row header + column header
Sticky column on mobile
The sticky first column uses position: sticky with a background that matches the row stripe, preventing ghost overlapping of content when scrolling horizontally.
Related components
- FeatureList — use for a single option's inclusions/exclusions when there is nothing to compare side-by-side.
- Chip — the "Recommended" indicator on a highlighted column is a Chip.