KKUONIDesign System

Components

Pill

Beta

Non-interactive label and status badge. Use for read-only categorisation, booking status, and decorative tags.

DefaultLuxuryNewArchivedConfirmedPendingCancelled

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

  1. Container
  2. Leading icon
  3. Label text

Variants

Default

Neutral grey — suitable for metadata and secondary attributes that do not carry semantic urgency.

Room onlyAdults onlyOcean view

Teal

Brand-teal highlight for premium or featured items.

LuxuryKuoni exclusiveEditor's pick

Yellow

Attention-grabbing warm accent for promotional or new content.

NewLimited offerEarly bird
Don't

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.

Sold outUnavailablePast trip

Semantic — success, warning, danger

Use these variants for booking and payment statuses where colour carries a clear meaning.

ConfirmedPending paymentCancelled

With icon

A leading icon reinforces meaning, especially in monochrome contexts or for users with colour-vision differences.

ConfirmedAwaiting depositLuxury
// 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

Do

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>
Don't

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>
Do

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>
Don't

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>
Do

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>
Don't

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 />
Do

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

PropTypeDefaultDescription
children*ReactNodeThe 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.
iconReactNodeOptional icon rendered before the children. Auto-sized to 12px to align with text-xs.
classNamestringAdditional CSS classes applied to the pill element.

Variant colour reference

VariantBackground tokenText tokenIntended use
defaultbg-grey-100text-grey-600General metadata, secondary attributes
tealbg-teal-50text-tealPremium, featured, brand highlight
yellowbg-kuoni-yellowtext-kuoni-darkPromotional, new content, early-bird
greybg-grey-50text-grey-500Inactive, archived, sold out
successbg-success-bgtext-successConfirmed, paid, complete
warningbg-warning-bgtext-warningPending, awaiting action
dangerbg-danger-bgtext-dangerCancelled, failed, error state

Accessibility

  • Pill renders as a span element. 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 icon prop, the icon must be aria-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.
  • 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.