Zostel
Trips & places Departure Picker

Departure Picker

A trip's departures, one to pick: the dates, the seats left and the price if given. The arrow keys move; a full one shows but can't be picked.

Preview

Kashmir in the snow, 7 days: pick a departure

Guests
2 guests

The departures and seats are samples. With a price per person, each row shows it.

Usage

tsx
import { DeparturePicker, QuantityStepper } from "zostel-ui";

<DeparturePicker
  aria-labelledby="departures-title"
  departures={trip.departures.map((d) => ({ id: d.id, from: d.start, to: d.end, seatsLeft: d.seats, price: formatPrice(d.price) }))}
  value={departure}
  onValueChange={setDeparture}
/>
<QuantityStepper label="Guests" value={guests} onValueChange={setGuests} min={1} />

Props

departures
Type: DepartureOption[]: { id; from: Date; to: Date; seatsLeft: number; price?: ReactNode }
Default: —

The departures in order: from and to are calendar days at local midnight (dayFromISO). seatsLeft of 0 or less shows Full: the arrow keys still reach it (aria-disabled, so a screen reader hears it’s full), but it can’t be picked. A departure whose days aren’t dates is left out, with a warning in development.

value · defaultValue · onValueChange
Type: string · string · (id) => void
Default: —

The departure picked (controlled, or uncontrolled from defaultValue). The rest of RadioGroup’s props (aria-labelledby, orientation, loop, name…) pass through.

label
Type: string
Default: "Departures"

The list’s name (or pass aria-labelledby).

className
Type: string
Default: —

More classes, merged with the component’s own (tailwind-merge).

On zostel.com

Every Zo Trip’s booking card: the departures, then the guests (the QuantityStepper), then Book now. A Radix radio group, so the arrow keys move between rows, and each row reads its dates in full.