Components
Accommodation Card
BetaAccommodationCard presents a hotel or resort listing with image, star rating, board basis, price, and a direct link — the primary unit for property-level search results and curated hotel grids.
Purpose
AccommodationCard is the property-level listing unit. It appears wherever a curated or filtered list of hotels is presented: the hotels section of a destination page, a "handpicked hotels" editorial module, search results filtered by destination, and the accommodation step of the booking funnel.
Where a TripCard presents a complete bookable holiday (flights + hotel + nights at a fixed price), an AccommodationCard presents the hotel property itself. The key distinction:
- TripCard — "7 nights at Soneva Fushi, flying from London, full board, from £4,250 per person"
- AccommodationCard — "Soneva Fushi · 5 stars · Full board · from £650 per person per night"
AccommodationCard links to the hotel detail page. It does not carry flight or departure context. The price shown is the hotel-only rate, often a nightly rate or a per-person-for-N-nights rate depending on the context.
Usage
Reach for AccommodationCard whenever the property itself — not a flight-inclusive package — is the thing being compared or browsed: hotel-only search results, a "handpicked hotels" module, or the accommodation-selection step of a booking funnel. If the item being presented bundles flights and nights at a fixed all-in price, use TripCard instead.
AccommodationCards are typically laid out in a 2–3 column grid on destination and search-results pages, and singly within a hotel comparison list. See Grid of cards below for layout guidance.
Anatomy
- 1Image — 3:2 aspect ratio, object-cover. Optional badge pill sits absolute top-right on the image (e.g. "New", "Save 20%") in kuoni-yellow.
- 2Star rating — Row of 1–5 gold filled star characters below the image. Uses the StarRow sub-component shared with TripCard.
- 3Hotel name — 16px bold. The primary identifier. Links to href.
- 4Location — 13px grey with a MapPin icon prepended. e.g. "Nungwi, Zanzibar".
- 5Board basis — 13px with a Utensils icon prepended. e.g. "All Inclusive", "Bed and Breakfast".
- 6Price block — Nights label above ("7 nights") when nights prop is set. "From £X" in 20px bold. "per person" in 12px grey below.
- 7CTA — "View hotel" teal text link that also points to href. Secondary affordance alongside the card-level link.
Variants
Standard
The most common variant. Image, stars, name, location, board basis, price, and CTA.
With badge
Use badge to highlight a property with a short promotional or editorial label. The badge renders in a kuoni-yellow pill in the top-right corner of the image.
Use badge for specific, time-limited promotions: 'Save 20%', 'Free upgrade', 'New property'.
The badge is the first element the eye reaches — use it for real, specific value.
Apply badge to the majority of cards in a grid as a default or to pad out the editorial selection.
Generic 'Featured' or 'Popular' badges on most cards lose their impact.
Featured
featured={true} gives the card a teal left border accent and a slightly elevated shadow. Use the featured variant to distinguish an editorially recommended property from a standard listing in the same grid — typically one featured card per section.
Use featured on at most one card per grid section to signal the editorial recommendation.
The featured variant creates a clear editorial hierarchy — one spotlight per section.
Apply featured to every card or more than one card per grid row.
Multiple featured cards in the same grid create visual noise and dilute the editorial choice.
No image
When image is omitted the card renders without the image block and the star rating moves to the top. Use in compact contexts such as a sidebar hotel list or a typeahead result.
Grid of cards
AccommodationCards are designed for 2–3 column grids. Avoid 4 columns — the card content becomes too compressed at common desktop widths.
States
Default
Card rests with a light shadow and a #E5E5E5 border on a white background. The "View hotel" CTA is teal, not underlined.
Hover
Shadow deepens, the card does not scale (content-dense cards avoid scale transforms). The hotel name underlines. The "View hotel" link underlines. Image zooms very slightly (scale(1.02)) within its clipped container.
Focus
When tabbed to, the card shows a visible teal focus ring (outline: 2px solid var(--color-teal); outline-offset: 2px) around the root <a> element.
Best practices
Always provide both nights and priceFrom together so the traveller understands the total price basis. A price without duration context is not meaningful for comparison.
'7 nights from £1,895 per person' is a complete, comparable data point.
Display priceFrom without setting nights when the price is for a fixed duration stay.
'From £1,895 per person' without nights context is ambiguous — per night? Per week?
Use starRating for the official hotel star classification (1–5). Display customer review scores using a separate Rating component.
Star rating describes official hotel classification — a separate signal from customer satisfaction.
Use starRating to show average customer review scores.
Mixing hotel classification stars with customer review stars in the same component confuses both signals.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| name* | string | — | Hotel or property name. Rendered as the primary heading in 16px bold. Also used as the accessible link text. |
| image | { src: string; alt: string } | — | Card hero image rendered at 3:2 aspect ratio with object-cover. When omitted the card renders without an image block. |
| location | string | — | Property location shown with a MapPin icon in 13px grey. e.g. 'Nungwi, Zanzibar', 'Baa Atoll, Maldives'. |
| starRating | number | — | Official hotel classification 1–5 stars. Renders gold filled star characters. Not for customer review scores. |
| boardBasis | string | — | Meal plan string shown with a Utensils icon. e.g. 'All Inclusive', 'Half Board', 'Bed and Breakfast', 'Room Only'. |
| priceFrom | number | — | Lead price numeral. Displayed as "From [currency][priceFrom]". |
| currency | string | '£' | Currency symbol prepended to the price numeral. |
| priceBasis | string | 'per person' | Suffix shown below the price. Defaults to 'per person'. Override for nightly rates: 'per person per night'. |
| nights | number | — | Number of nights. When provided, renders '[N] nights' above the price to give the price context. |
| href | string | — | URL of the hotel detail page. The hotel name and the "View hotel" CTA both link here. |
| badge | string | — | Short label rendered in a kuoni-yellow pill on the top-right of the image. e.g. 'New', 'Save 20%', 'Free upgrade'. |
| featured | boolean | false | When true, applies a teal left border accent and a slightly elevated shadow to distinguish the card as an editorial pick. |
| className | string | — | Additional Tailwind classes on the root element. |
Accessibility
Card link structure
The card root is an <a> tag pointing to href. The hotel name inside is an <h3> (or the appropriate heading rank for the page). Screen readers read:
- Image alt text (describes the scene, not just the name)
- Hotel name (heading)
- Location
- Board basis
- Price
- "View hotel" (secondary link text)
The "View hotel" link is a second <a> tag pointing to the same href. It is aria-hidden="true" with tabIndex={-1} because the parent card link already covers the same destination — duplicate links in the tab order create unnecessary noise for keyboard users.
Image alt text
Alt text describes the visual scene, not the property name. The property name is already in the name prop.
{/* ✅ */}
image={{ alt: 'Infinity pool at dusk with the Indian Ocean beyond' }}
{/* ❌ Redundant — name already says 'Nungwi Beach Resort' */}
image={{ alt: 'Nungwi Beach Resort pool' }}
Star rating
The StarRow sub-component renders aria-label="N out of 5 stars" on its container. The individual star characters are aria-hidden. Screen readers hear "4 out of 5 stars" without reading "★★★★".
Badge
The badge text is part of the <a> link and will be read by screen readers. Write badge text so it makes sense when read in context: "Save 20%" is clear; "Hot" is ambiguous.
Focus ring
The card focus ring is 2px solid var(--color-teal) with a 2px offset, visible against both white and tinted backgrounds. The ring appears on the outer <a> element, not on child elements, so keyboard users see one consistent focus indicator per card.
Related components
- TripCard — use instead when the listing is a flight-inclusive package rather than a hotel-only rate.
- ActivityCard — the equivalent card pattern for excursions and experiences rather than properties.
- Card — the generic container this and other card components specialise for a specific content type.