Components
Board Basis Selector
BetaA segmented option picker for selecting a meal plan or board basis. Shows price differentials between options and highlights the current selection in teal.
Choose your board basis
Purpose
The BoardBasisSelector lets customers quickly switch between meal plan options during the booking flow. Unlike a generic Select dropdown, it lays all options out simultaneously — removing the need to open a menu to compare. This is especially valuable for board basis because price differences between options are a key decision factor.
It appears in:
- Booking funnel — step 2 or 3, after choosing room type
- Holiday detail page — alongside price to show what changes with board basis
- Quote builder — where agents or customers customise a package
Usage
Reach for BoardBasisSelector when a small, fixed set of board basis options (4 or fewer) needs to be compared side by side with visible price differentials. For 5 or more options, or when price comparison isn't the primary decision driver, use a Select dropdown instead.
It sits within the booking funnel's room/board step, on the holiday detail page price panel, or inside a quote builder — always adjacent to the price it affects.
Anatomy
Board basis
- 1Label — 14px medium weight group label above the buttons. e.g. "Board basis".
- 2Option button — Rounded card button for each option. Unselected = white bg + grey border. Selected = teal-50 bg + teal border + teal text.
- 3Option label — Bold short name. e.g. "Half Board", "All Inclusive".
- 4Option description — Optional secondary line. e.g. "Breakfast and evening meal included".
- 5Price differential — Shown below description. +£N pp = grey, -£N pp = green, 0 = "Included" (base price).
Variants
With descriptions
Add description to each option to explain what the board basis includes.
Board basis
Without price differentials
Set showPriceDiff={false} when all options are the same price, or when price is displayed separately.
Meal plan
With a disabled option
Pass disabled: true on an option to mark it unavailable (e.g. All Inclusive not available at this property).
Board basis
States
| State | Appearance |
|---|---|
| Unselected | White bg, grey-200 border, kuoni-dark text |
| Selected | Teal-50 bg, teal border, teal text |
| Hover (unselected) | Teal border (border transitions) |
| Disabled option | 50% opacity, cursor-not-allowed |
| Full group disabled | All options unclickable |
Best practices
Always show price differentials when options have different prices — it is the primary decision driver.
Price differentials like '+£150 pp' let customers decide instantly without recalculating.
Remove price differentials to keep the UI clean — they are essential for board basis decisions.
Hiding the price differential forces users to go back and recalculate after selecting.
Keep options to 4 or fewer. If a resort offers more than 4 board basis options, use a Select dropdown instead.
3-4 options lay out cleanly in a row on desktop. More wrap onto two rows.
Use BoardBasisSelector for 5 or more options — Switch to Select component.
5+ pill buttons start to wrap inconsistently and lose the at-a-glance comparison benefit.
Always set a defaultValue or value — leaving all options unselected forces an unnecessary extra step.
Pre-selecting the most common option (Bed and Breakfast) reduces friction for the majority of users.
Leave the selector without a default value in the booking funnel.
No pre-selection on the board basis step means users must explicitly choose even if the default suits them.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| options* | Array<{ value: string; label: string; description?: string; priceDiff?: number; disabled?: boolean }> | — | Array of board basis options. priceDiff: positive=extra cost, negative=saving, 0=base price (shows "Included"). |
| value | string | — | Controlled selected option value. Parent manages state when provided. |
| defaultValue | string | first option | Initial selection for uncontrolled usage. |
| onChange | (value: string, option: object) => void | — | Called when a new option is selected. |
| disabled | boolean | false | Disables all options in the group. |
| label | string | 'Board basis' | Group label shown above the options. |
| showPriceDiff | boolean | true | Whether to show the price differential below each option label. |
| className | string | — | Additional Tailwind classes on the root container. |
Accessibility
Radio group semantics
BoardBasisSelector renders with role="radiogroup" on the container and role="radio" with aria-checked on each button. This matches the single-selection semantic of a radio group.
<div role="radiogroup" aria-label="Board basis">
<button role="radio" aria-checked={false}>Bed and Breakfast</button>
<button role="radio" aria-checked={true}>Half Board</button>
</div>
Keyboard interaction
| Key | Action |
|---|---|
Tab | Move focus to the group, then through each option |
Enter / Space | Select the focused option |
| Arrow keys | Not implemented — use Tab to navigate between options |
Price differential
The price differential text (+£150 pp, -£200 pp, Included) is included in the accessible name of each button, so screen readers announce the full option including cost impact.
Related components
- Select — use instead when there are 5 or more board basis options.