Components
Pill
BetaNon-interactive label and status badge. Use for read-only categorisation, booking status, and decorative tags.
Purpose
Pill is a purely decorative inline label. It communicates a category, status, or attribute without any interactive affordance. Unlike Chip, a Pill cannot be clicked, toggled, or removed — it only displays information.
Use Pill when:
- Showing a booking status (Confirmed, Pending, Cancelled)
- Labelling a room or package category (Luxury, Family, Adults only)
- Highlighting new or promotional content (New, Sale, Limited)
- Displaying a read-only attribute alongside a card title or table cell
Use Chip instead when the traveller needs to select or deselect the item as a filter.
Usage
Reach for Pill whenever the content is read-only status or metadata — a booking state, a category tag, a promotional label. As soon as the user needs to select, deselect, or remove the item, switch to Chip, which shares the same visual language but adds interactivity.
Pills appear inline next to card titles, in table status columns, and as small category tags on listing pages.
Anatomy
- Container
- Leading icon
- Label text
Variants
Default
Neutral grey — suitable for metadata and secondary attributes that do not carry semantic urgency.
Teal
Brand-teal highlight for premium or featured items.
Yellow
Attention-grabbing warm accent for promotional or new content.
The yellow variant is reserved for promotional signals (New, Sale, Limited). Using it for a booking status like 'On hold' will clash with the promotional meaning it has elsewhere.
// Avoid for status
<Pill variant="yellow">On hold</Pill>
// Prefer
<Pill variant="warning">On hold</Pill>
Grey
Subtle muted label for archived, inactive, or de-emphasised content.
Semantic — success, warning, danger
Use these variants for booking and payment statuses where colour carries a clear meaning.
With icon
A leading icon reinforces meaning, especially in monochrome contexts or for users with colour-vision differences.
// Icon usage example — pass any ReactNode as the icon prop
import { CheckCircleIcon } from '@heroicons/react/16/solid'
<Pill variant="success" icon={<CheckCircleIcon />}>Confirmed</Pill>
<Pill variant="warning" icon={<ClockIcon />}>Awaiting deposit</Pill>
States
Pill is stateless — it has no hover, focus, active, or disabled states because it carries no interactivity. It renders identically at all times.
If your design requires a greyed-out version of a normally coloured pill (e.g. a "Cancelled" status shown less prominently), use variant="grey" rather than adding custom opacity.
Best practices
Colour communicates at a glance. Match the variant to the outcome: success for positive, warning for pending, danger for negative.
<Pill variant="success">Confirmed</Pill>
<Pill variant="warning">Pending</Pill>
<Pill variant="danger">Cancelled</Pill>
Adding custom background or text colours breaks the design token system and makes status meanings inconsistent across the product.
// Avoid
<Pill className="bg-purple-200 text-purple-800">VIP</Pill>
// Prefer — use the closest semantic variant or request a new one
<Pill variant="teal">VIP</Pill>
One to three words is ideal. Pills at text-xs with padding px-2.5 py-0.5 are designed for brief labels.
<Pill variant="teal">Luxury</Pill>
<Pill variant="success">Confirmed</Pill>
Pill is not a banner or callout. Long strings overflow, truncate unexpectedly, and lose their compact visual purpose.
// Avoid
<Pill variant="warning">Your payment is due in 3 days</Pill>
// Prefer — use an Alert or InlineMessage component
<Alert variant="warning">Your payment is due in 3 days.</Alert>
Pill is the right choice for the 'Status' column in a bookings table — compact, consistent, no interaction required.
<td>
<Pill variant={statusVariant(booking.status)}>
{booking.statusLabel}
</Pill>
</td>
If the label should be toggleable, use Chip. A Pill that looks clickable but does nothing creates confusion.
// Avoid — travellers will try to click this to filter
<div className="flex gap-2 cursor-pointer" onClick={toggleBeach}>
<Pill variant="teal">Beach</Pill>
</div>
// Prefer
<Chip label="Beach" defaultSelected />
Colour alone should not be the only signal. A small icon alongside success/warning/danger pills helps travellers with colour-vision differences.
<Pill variant="danger" icon={<XCircleIcon />}>Cancelled</Pill>
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| children* | ReactNode | — | The label text or content rendered inside the pill. |
| variant | 'default' | 'teal' | 'yellow' | 'grey' | 'success' | 'warning' | 'danger' | 'default' | Controls the background and text colour of the pill. |
| icon | ReactNode | — | Optional icon rendered before the children. Auto-sized to 12px to align with text-xs. |
| className | string | — | Additional CSS classes applied to the pill element. |
Variant colour reference
| Variant | Background token | Text token | Intended use |
|---|---|---|---|
| default | bg-grey-100 | text-grey-600 | General metadata, secondary attributes |
| teal | bg-teal-50 | text-teal | Premium, featured, brand highlight |
| yellow | bg-kuoni-yellow | text-kuoni-dark | Promotional, new content, early-bird |
| grey | bg-grey-50 | text-grey-500 | Inactive, archived, sold out |
| success | bg-success-bg | text-success | Confirmed, paid, complete |
| warning | bg-warning-bg | text-warning | Pending, awaiting action |
| danger | bg-danger-bg | text-danger | Cancelled, failed, error state |
Accessibility
- Pill renders as a
spanelement. It carries no interactive role and is not focusable. - Because Pill is a purely visual element that appears inline with other content, it does not need an explicit ARIA role.
- When colour is the primary differentiator (e.g. a status column), always accompany the pill with a text label inside it — never use an icon-only pill for status. This satisfies WCAG 1.4.1 (Use of Colour).
- When using an
iconprop, the icon must bearia-hidden="true"(the icon itself carries no meaning — the visible text label does). - Pill text must meet the WCAG AA contrast ratio of 4.5:1. All default variant/colour combinations in the table above are designed to pass; do not override colours with custom classes that may reduce contrast.
Related components
- Chip — the interactive counterpart; use instead of Pill when the traveller needs to select, deselect, or remove the item.
- Badge — another small decorative label; choose based on which visual language the surrounding component family already uses.
- NotificationBadge — for a count or dot overlay on an icon trigger, rather than an inline status label.