Room Option
A room or a bed to add to the stay: picture, who it sleeps, what's in it, a note, the nights it's free, its rate and Select.
Preview

6 bed mixed dorm
Sleeps 1A bed in a mixed dorm with a locker of your own and a shared washroom.
Stay three nights or more and the house rate drops.
- Free Wi-Fi
- Lockers
- Bunk bed
- A plug by the bed
- Towels
Bed only
Rates on your dates

Deluxe private room
Sleeps 2A room of your own with a double bed and a balcony over the valley.
The last one on your dates.
- Free Wi-Fi
- Private room
- Mountain view
- Towels
Room only
Rates on your dates
4 bed female dorm
Sleeps 1A bed in a female dorm with a locker of your own and its own washroom.
- Free Wi-Fi
- Lockers
- Bunk bed
- A plug by the bed
- Towels
The rooms, notes and nights are samples; the pictures are Manali's covers and its landscape, standing in for photos.
Usage
import { RoomOption, ZostelIcon } from "zostel-ui";
<RoomOption
name="6 bed mixed dorm"
description="A bed in a mixed dorm with a locker of your own."
sleeps={1}
imageUrl={room.photo}
onPhotos={() => openGallery(room.id)}
amenities={[{ icon: <ZostelIcon set="zostel-ui" name="wifi" color="currentColor" />, label: "Free Wi-Fi" }]}
price={formatPrice(room.rate)}
unit="bed"
quantity={beds}
maxQuantity={room.left}
onQuantityChange={setBeds}
availability={room.nights}
/>Props
| Prop | Type | Default | Description |
|---|---|---|---|
name | string | — | The room or bed. |
description · note | string · ReactNode | — | What it is; a rule or an offer, in italics. |
sleeps | number | — | Who it sleeps: “Sleeps 2”. |
imageUrl · onPhotos | string · () => void | — | Its picture; onPhotos makes the picture a button to the room’s photos (PhotoGallery with open and group). |
amenities | { icon: ReactNode; label: string }[] | — | What’s in it: each glyph with its name beside it, on every screen (a finger can’t hover, and nobody reads glyphs alone). |
plan | ReactNode | — | The rate plan the price belongs to, over it (“Bed only”, “With breakfast”). |
price · priceUnit | ReactNode · string | — · "/ night" | The rate as you print it, and what follows it. |
quantity · onQuantityChange · maxQuantity | number · (n) => void · number | — | How many are picked: 0 shows Select, more shows the stepper, up to maxQuantity. quantity and onQuantityChange come together (without them the room shows no Select). When Select and the stepper swap, the focus moves with them only if it was on the one that left: to the stepper’s first button that can act, or back to Select. |
unit | "bed" | "room" | "bed" | “Select bed” or “Select room”; the stepper counts beds or rooms. |
soldOut | boolean | — | Nothing left on these dates: the picture greys, it says Sold out, and the nights that are free open below. What was already picked stays in the stay: the stepper remains, to take some out but add none. |
titleAs | "h2" | "h3" | "h4" | "p" | "h3" | The name’s element, so it sits in the page’s outline. |
availability | { date: Date; left: number; price? }[] | — | Night by night, what’s free: the calendar button opens it (AvailabilityStrip). |
className | string | — | More classes, merged with the component’s own (tailwind-merge). |
namestringThe room or bed.
description · notestring · ReactNodeWhat it is; a rule or an offer, in italics.
sleepsnumberWho it sleeps: “Sleeps 2”.
imageUrl · onPhotosstring · () => voidIts picture; onPhotos makes the picture a button to the room’s photos (PhotoGallery with open and group).
amenities{ icon: ReactNode; label: string }[]What’s in it: each glyph with its name beside it, on every screen (a finger can’t hover, and nobody reads glyphs alone).
planReactNodeThe rate plan the price belongs to, over it (“Bed only”, “With breakfast”).
price · priceUnitReactNode · string— · "/ night"The rate as you print it, and what follows it.
quantity · onQuantityChange · maxQuantitynumber · (n) => void · numberHow many are picked: 0 shows Select, more shows the stepper, up to maxQuantity. quantity and onQuantityChange come together (without them the room shows no Select). When Select and the stepper swap, the focus moves with them only if it was on the one that left: to the stepper’s first button that can act, or back to Select.
unit"bed" | "room""bed"“Select bed” or “Select room”; the stepper counts beds or rooms.
soldOutbooleanNothing left on these dates: the picture greys, it says Sold out, and the nights that are free open below. What was already picked stays in the stay: the stepper remains, to take some out but add none.
titleAs"h2" | "h3" | "h4" | "p""h3"The name’s element, so it sits in the page’s outline.
availability{ date: Date; left: number; price? }[]Night by night, what’s free: the calendar button opens it (AvailabilityStrip).
classNamestringMore classes, merged with the component’s own (tailwind-merge).
On zostel.com
The heart of a stay’s page: one per dorm and room type, with the booking bar beside them. Select swaps for the stepper under the finger and back, and the focus goes with it, so the keyboard never loses its place (with the last room, “Add one” is off from the start, so the focus lands on “Remove one”).