CriteriaTransports

PreviousNext

A transport selection panel that lets users opt in to Club Med transportation and pick a departure airport from grouped, scrollable lists.

Transport

Add transportation from

Top cities

Boston Logan International (BOS)
New York all airports (NYC)
Miami International (MIA)
Los Angeles International (LAX)
San Francisco International (SFO)

Other cities

Albuquerque (ABQ)
Anchorage International (ANC)
Atlanta Hartsfield-Jackson (ATL)
Austin-Bergstrom International (AUS)
Nashville International (BNA)
Buffalo Niagara International (BUF)
Charlotte Douglas International (CLT)
John Glenn Columbus International (CMH)
Dallas Love Field (DAL)
Denver International (DEN)
Detroit Metropolitan Wayne County (DTW)
Daniel K. Inouye International (HNL)
Washington Dulles International (IAD)
Indianapolis International (IND)
Jacksonville International (JAX)
Harry Reid International (LAS)
Kansas City International (MCI)
Orlando International (MCO)
Chicago Midway International (MDW)
Memphis International (MEM)
Minneapolis-Saint Paul International (MSP)
Louis Armstrong New Orleans International (MSY)
Oakland Metropolitan International (OAK)
Chicago O'Hare International (ORD)
Philadelphia International (PHL)
Phoenix Sky Harbor International (PHX)
Pittsburgh International (PIT)
Portland International (PDX)
Raleigh-Durham International (RDU)
Southwest Florida International (RSW)
San Diego International (SAN)
San Antonio International (SAT)
Seattle-Tacoma International (SEA)
Norman Y. Mineta San José International (SJC)
Salt Lake City International (SLC)
Sacramento International (SMF)
John Wayne Airport Orange County (SNA)
St. Louis Lambert International (STL)
Tampa International (TPA)
Tulsa International (TUL)

Opt for Club Med transportation:

Assistance and support in case of unforeseen events. Comfort guaranteed from departure to arrival.

'use client';
import { useState } from 'react';

import { CriteriaTransports } from '@/ui/criteria/CriteriaTransports';
import type { CriteriaTransportsProps } from '@/ui/criteria/CriteriaTransports';

const labels: CriteriaTransportsProps['labels'] = {
  toggleLabel: 'Add transportation from',
  topCitiesLabel: 'Top cities',
  otherCitiesLabel: 'Other cities',
  clubMedTransportTitle: 'Opt for Club Med transportation:',
  clubMedTransportDescription:
    'Assistance and support in case of unforeseen events. Comfort guaranteed from departure to arrival.',
  reset: 'Reset',
  apply: 'Continue',
};

const topCities = [
  { code: 'BOS', name: 'Boston Logan International (BOS)' },
  { code: 'NYC', name: 'New York all airports (NYC)' },
  { code: 'MIA', name: 'Miami International (MIA)' },
  { code: 'LAX', name: 'Los Angeles International (LAX)' },
  { code: 'SFO', name: 'San Francisco International (SFO)' },
];

const otherCities = [
  { code: 'ABQ', name: 'Albuquerque (ABQ)' },
  { code: 'ANC', name: 'Anchorage International (ANC)' },
  { code: 'ATL', name: 'Atlanta Hartsfield-Jackson (ATL)' },
  { code: 'AUS', name: 'Austin-Bergstrom International (AUS)' },
  { code: 'BNA', name: 'Nashville International (BNA)' },
  { code: 'BUF', name: 'Buffalo Niagara International (BUF)' },
  { code: 'CLT', name: 'Charlotte Douglas International (CLT)' },
  { code: 'CMH', name: 'John Glenn Columbus International (CMH)' },
  { code: 'DAL', name: 'Dallas Love Field (DAL)' },
  { code: 'DEN', name: 'Denver International (DEN)' },
  { code: 'DTW', name: 'Detroit Metropolitan Wayne County (DTW)' },
  { code: 'HNL', name: 'Daniel K. Inouye International (HNL)' },
  { code: 'IAD', name: 'Washington Dulles International (IAD)' },
  { code: 'IND', name: 'Indianapolis International (IND)' },
  { code: 'JAX', name: 'Jacksonville International (JAX)' },
  { code: 'LAS', name: 'Harry Reid International (LAS)' },
  { code: 'MCI', name: 'Kansas City International (MCI)' },
  { code: 'MCO', name: 'Orlando International (MCO)' },
  { code: 'MDW', name: 'Chicago Midway International (MDW)' },
  { code: 'MEM', name: 'Memphis International (MEM)' },
  { code: 'MSP', name: 'Minneapolis-Saint Paul International (MSP)' },
  { code: 'MSY', name: 'Louis Armstrong New Orleans International (MSY)' },
  { code: 'OAK', name: 'Oakland Metropolitan International (OAK)' },
  { code: 'ORD', name: "Chicago O'Hare International (ORD)" },
  { code: 'PHL', name: 'Philadelphia International (PHL)' },
  { code: 'PHX', name: 'Phoenix Sky Harbor International (PHX)' },
  { code: 'PIT', name: 'Pittsburgh International (PIT)' },
  { code: 'PDX', name: 'Portland International (PDX)' },
  { code: 'RDU', name: 'Raleigh-Durham International (RDU)' },
  { code: 'RSW', name: 'Southwest Florida International (RSW)' },
  { code: 'SAN', name: 'San Diego International (SAN)' },
  { code: 'SAT', name: 'San Antonio International (SAT)' },
  { code: 'SEA', name: 'Seattle-Tacoma International (SEA)' },
  { code: 'SJC', name: 'Norman Y. Mineta San José International (SJC)' },
  { code: 'SLC', name: 'Salt Lake City International (SLC)' },
  { code: 'SMF', name: 'Sacramento International (SMF)' },
  { code: 'SNA', name: 'John Wayne Airport Orange County (SNA)' },
  { code: 'STL', name: 'St. Louis Lambert International (STL)' },
  { code: 'TPA', name: 'Tampa International (TPA)' },
  { code: 'TUL', name: 'Tulsa International (TUL)' },
];

export function CriteriaTransportsDemo() {
  const [enabled, setEnabled] = useState(false);
  const [selected, setSelected] = useState<string | null>(null);

  return (
    <div className="w-[380px] space-y-24">
      <CriteriaTransports
        labels={labels}
        title="Transport"
        enabled={enabled}
        topCities={topCities}
        otherCities={otherCities}
        selectedAirportCode={selected}
        onToggle={setEnabled}
        onSelect={setSelected}
        onReset={() => {
          setEnabled(false);
          setSelected(null);
        }}
        onApply={() => {}}
      />
      {selected && (
        <p className="text-b4">
          Selected: <strong>{selected}</strong>
        </p>
      )}
    </div>
  );
}

Installation

npx shadcn@latest add https://develop.trident-ui.pro.clubmed/r/criteria-transports.json

Usage

import { CriteriaTransports } from '@/ui/criteria/CriteriaTransports';
 
export function Component() {
  const [enabled, setEnabled] = useState(false);
  const [selected, setSelected] = useState<string | null>(null);
 
  return (
    <CriteriaTransports
      labels={{
        toggleLabel: 'Add transportation from',
        topCitiesLabel: 'Top cities',
        otherCitiesLabel: 'Other cities',
        clubMedTransportTitle: 'Opt for Club Med transportation:',
        clubMedTransportDescription:
          'Assistance and support in case of unforeseen events.',
        reset: 'Reset',
        apply: 'Continue',
      }}
      title="Transport"
      enabled={enabled}
      topCities={[
        { code: 'BOS', name: 'Boston Logan International (BOS)' },
        { code: 'NYC', name: 'New York all airports (NYC)' },
      ]}
      otherCities={[
        { code: 'ABQ', name: 'Albuquerque (ABQ)' },
      ]}
      selectedAirportCode={selected}
      onToggle={setEnabled}
      onSelect={setSelected}
      onReset={() => { setEnabled(false); setSelected(null); }}
      onApply={() => {}}
    />
  );
}

B2B Mode

The component supports a B2B booking flow via the mode="b2b" prop. In this mode, additional flight configuration fields (flight type, cabin class, and departure) appear above the airport list when transport is enabled. A single error prop covers the case where a prerequisite — such as resort selection — has not been met.

Transport

Add transportation from

Top cities

Boston Logan International (BOS)
New York all airports (NYC)
Miami International (MIA)

Other cities

Albuquerque (ABQ)
Anchorage International (ANC)
Atlanta Hartsfield-Jackson (ATL)
Austin-Bergstrom International (AUS)
Denver International (DEN)
Los Angeles International (LAX)
Seattle-Tacoma International (SEA)
San Francisco International (SFO)

Opt for Club Med transportation:

Assistance and support in case of unforeseen events. Comfort guaranteed from departure to arrival.

'use client';
import { useState } from 'react';

import { CriteriaTransports } from '@/ui/criteria/CriteriaTransports';
import type {
  CriteriaTransportsProps,
  CriteriaTransportsB2BLabels,
} from '@/ui/criteria/CriteriaTransports';
import type { RadioSelectOption } from '@/ui/forms/RadioSelect';

const labels: CriteriaTransportsProps['labels'] = {
  toggleLabel: 'Add transportation from',
  topCitiesLabel: 'Top cities',
  otherCitiesLabel: 'Other cities',
  clubMedTransportTitle: 'Opt for Club Med transportation:',
  clubMedTransportDescription:
    'Assistance and support in case of unforeseen events. Comfort guaranteed from departure to arrival.',
  reset: 'Reset',
  apply: 'Confirm',
};

const b2bLabels: CriteriaTransportsB2BLabels = {
  roundTripLabel: 'Round trip',
  oneWayLabel: 'One way',
  cabinClassLabel: 'Class',
  departureDateLabel: 'From',
};

const cabinClassOptions: RadioSelectOption<string>[] = [
  { value: 'all', label: 'All classes' },
  { value: 'economy', label: 'Economy' },
  { value: 'business', label: 'Business' },
  { value: 'first', label: 'First class' },
];

const topCities = [
  { code: 'BOS', name: 'Boston Logan International (BOS)' },
  { code: 'NYC', name: 'New York all airports (NYC)' },
  { code: 'MIA', name: 'Miami International (MIA)' },
];

const otherCities = [
  { code: 'ABQ', name: 'Albuquerque (ABQ)' },
  { code: 'ANC', name: 'Anchorage International (ANC)' },
  { code: 'ATL', name: 'Atlanta Hartsfield-Jackson (ATL)' },
  { code: 'AUS', name: 'Austin-Bergstrom International (AUS)' },
  { code: 'DEN', name: 'Denver International (DEN)' },
  { code: 'LAX', name: 'Los Angeles International (LAX)' },
  { code: 'SEA', name: 'Seattle-Tacoma International (SEA)' },
  { code: 'SFO', name: 'San Francisco International (SFO)' },
];

export function CriteriaTransportsB2BDemo() {
  const [enabled, setEnabled] = useState(false);
  const [selected, setSelected] = useState<string | null>(null);
  const [flightType, setFlightType] = useState<'roundtrip' | 'oneway'>('roundtrip');
  const [cabinClass, setCabinClass] = useState<string | undefined>(undefined);
  const [departureQuery, setDepartureQuery] = useState('');

  return (
    <div className="w-[380px] space-y-24">
      <CriteriaTransports
        mode="b2b"
        labels={labels}
        b2bLabels={b2bLabels}
        title="Transport"
        enabled={enabled}
        topCities={topCities}
        otherCities={otherCities}
        selectedAirportCode={selected}
        flightType={flightType}
        cabinClass={cabinClass}
        cabinClassOptions={cabinClassOptions}
        departureQuery={departureQuery}
        onToggle={setEnabled}
        onSelect={setSelected}
        onFlightTypeChange={setFlightType}
        onCabinClassChange={(_event, value) => setCabinClass(value)}
        onDepartureQueryChange={(_event, value) => setDepartureQuery(value)}
        onReset={() => {
          setEnabled(false);
          setSelected(null);
          setFlightType('roundtrip');
          setCabinClass(undefined);
          setDepartureQuery('');
        }}
        onApply={() => {}}
      />
      {selected && (
        <p className="text-b4">
          Selected: <strong>{selected}</strong>
        </p>
      )}
    </div>
  );
}

Error state

Pass an error string to display an error card instead of the B2B form. This is used when a prerequisite (e.g. selecting a resort) has not been completed.

<CriteriaTransports
  mode="b2b"
  enabled
  error="Please select a resort before choosing transport."
  {/* ...other required props */}
/>

API Reference

CriteriaTransports

PropTypeDefaultDescription
labelsCriteriaTransportsLabels—Required. Localized strings for all visible text.
titlestring—Optional section heading rendered above the toggle.
variant'card' | 'flat''card'card wraps content in a white bordered card with a sand inner panel. flat renders fields without any card background.
mode'b2c' | 'b2b''b2c'Switches between B2C and B2B layouts. B2B adds flight type, cabin class, and departure selectors above the airport list.
enabledboolean—Controls whether transport selection is active (toggle on/off).
topCitiesAirport[]—Promoted airports shown under the "Top cities" heading.
otherCitiesAirport[]—Full airport list shown under the "Other cities" heading.
selectedAirportCodestring | null—Code of the currently selected airport, or null for no selection.
classNamestring—Extra CSS classes applied to the root element.
onToggle(enabled: boolean) => void—Called when the user flips the transport toggle.
onSelect(code: string | null) => void—Called with the airport code on selection, or null when deselecting.
onReset() => void—When provided, renders a "Reset" link in the footer.
onApply() => void—When provided, renders a "Continue/Confirm" button in the footer.
b2bLabelsCriteriaTransportsB2BLabels—Required in B2B mode. Localized strings for the B2B-specific fields.
flightType'roundtrip' | 'oneway''roundtrip'Currently selected flight type (B2B mode).
onFlightTypeChange(type: 'roundtrip' | 'oneway') => void—Called when the user changes the flight type radio (B2B mode).
cabinClassstring—Currently selected cabin class value. Passed to the RadioSelect trigger (B2B mode).
cabinClassOptionsRadioSelectOption<string>[]—Options list for the cabin class RadioSelect dropdown (B2B mode).
onCabinClassChange(event: Event, value: string) => void—Called when the user picks a cabin class from the dropdown (B2B mode).
departureQuerystring—Controlled value for the departure TextField; also filters the airport list below (B2B mode).
onDepartureQueryChange(event: Event, value: string) => void—Called as the user types in the departure field (B2B mode).
errorstring—Error message shown in B2B mode instead of the flight form when a prerequisite is missing.

Airport

FieldTypeDescription
codestringIATA airport code (e.g. "BOS"). Used as the selection key.
namestringFull display label (e.g. "Boston Logan International (BOS)").

CriteriaTransportsLabels

FieldTypeDescription
toggleLabelstringLabel next to the on/off switch (e.g. "Add transportation from").
topCitiesLabelstringGroup heading for promoted airports.
otherCitiesLabelstringGroup heading for remaining airports.
clubMedTransportTitlestringTitle inside the Club Med transport info card (toggle off state).
clubMedTransportDescriptionstringBody text inside the Club Med transport info card.
resetstringLabel for the reset link. Required when onReset is provided.
applystringLabel for the continue/confirm button. Required when onApply is provided.

CriteriaTransportsB2BLabels

FieldTypeDescription
roundTripLabelstringLabel for the round-trip radio option (e.g. "Round trip").
oneWayLabelstringLabel for the one-way radio option (e.g. "One way").
cabinClassLabelstringField label for the cabin class selector (e.g. "Class").
departureDateLabelstringField label for the departure date/city field (e.g. "From").

Behaviour

  • Toggle off — Displays a Club Med transport info card explaining the benefits of booking transport. No airport selection is available (same in both B2C and B2B modes).
  • Toggle on (B2C) — Hides the info card and reveals a scrollable airport list grouped into "Top cities" and "Other cities". Either group is omitted when its array is empty.
  • Toggle on (B2B, no error) — Shows flight type radio buttons, a cabin class selector, a departure date/city field, then the airport list below.
  • Toggle on (B2B, with error) — Shows an error card with the error message instead of the B2B form. Use this when a prerequisite step (e.g. resort selection) must be completed first.
  • Flight type (B2B) — Radio group (using the Radio component) allowing single selection between round-trip and one-way. Fully controlled via flightType and onFlightTypeChange.
  • Cabin class (B2B) — Uses the RadioSelect component. Pass cabinClassOptions to populate the dropdown and cabinClass for the controlled value. onCabinClassChange fires (event, value) on selection.
  • Departure field (B2B) — Uses the TextField component with a calendar icon. departureQuery controls the input value; onDepartureQueryChange fires (event, value) on every keystroke. The same query also filters the airport list shown below the field.
  • Airport selection — Single select: clicking an already-selected airport calls onSelect(null) to deselect it. The selected item is styled with a black background and white text.
  • Scroll — The airport list container is capped at max-h-[420px] with overflow-y-auto, so long lists scroll without expanding the card.
  • Footer — Rendered only when at least one of onReset or onApply is provided.

Accessibility

  • The toggle uses role="switch" via the Switch component.
  • The flight type selector uses a native <input type="radio"> group with visible labels, ensuring full keyboard and screen reader support.
  • Each airport item carries role="option" and aria-selected to communicate selection state.
  • The cabin class selector uses RadioSelect, which renders a <button aria-haspopup="listbox"> trigger and a role="listbox" dropdown with radio options — fully keyboard navigable.
  • The departure field uses TextField, which renders a standard <input> with a visible label and calendar icon — supports all native keyboard interactions.
  • The continue and reset buttons are native <button> elements with visible labels.