Zostel
Stays Booking Bar

Booking Bar

What the stay comes to and the one way on, always in reach: the dates, the amount, the action. It floats on a phone and sits beside the rooms on a desk.

Preview

Your stay

No dates yet

Got a group trip in mind?

In the flow here. On a phone, position="fixed" floats it at the foot of the screen.

Usage

tsx
import { BookingBar, Button, DateRangePicker, CurrencyPicker } from "zostel-ui";

{/* a phone: floats at the foot of the screen; the page's end keeps room for it */}
<main className="pb-[var(--booking-bar-h)]">…</main>
<BookingBar
  position="fixed"
  className="lg:hidden"
  dates={<DateRangePicker aria-label="Your dates" from={from} to={to} onRangeChange={setDates} />}
  aside={<CurrencyPicker currencies={currencies} value={code} onValueChange={setCode} />}
  label="Payable now"
  amount={payable}
  action={<Button onClick={openSummary}>View summary</Button>}
/>

{/* a desk: the same card beside the rooms, 1rem under the header */}
<BookingBar position="sticky" className="hidden lg:block" … />

/* your header's height, once, on :root: every sticky part (this bar, SectionNav) pins under it */
:root { --header-h: 4.5rem; }

Props

position
Type: "static" | "sticky" | "fixed"
Default: "static"

fixed floats it at the foot of the screen, clear of the home bar (z 40, under the header’s 50), and writes how much of the screen it covers to --booking-bar-h; base.css gives that to scroll-padding-bottom, so a field that takes the focus scrolls clear of the bar (WCAG 2.4.11). Give the page’s end the same room (pb-[var(--booking-bar-h)] on the main container), so the last field can scroll above it too. sticky keeps a sidebar card 1rem under the header (top: var(--header-h) + 1rem; set --header-h to your header’s height). static leaves it in the flow.

dates · aside
Type: ReactNode
Default: —

The top row: a DateRangePicker, and beside it a CurrencyPicker.

label · amount
Type: ReactNode
Default: —

“From” or “Payable now”, and the amount as you print it (0 included; or words before anything is picked). Together they are a status: a screen reader hears the new total when it changes.

action
Type: ReactNode
Default: —

The one action: your Button.

footer
Type: ReactNode
Default: —

A last line under a rule: another way to book.

aria-label
Type: string
Default: "Your booking"

The bar’s name.

className
Type: string
Default: —

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

On zostel.com

On a phone it rides at the foot of every stay’s page (the dates, the currency, what’s payable and View summary); on a desk the same card sits at the top of the sidebar. Flat, like every panel in the kit: a Beige edge, no shadow, even floating.