BookingSummary
What was booked: the place and picture, dates in and out with the nights counted, guests, price lines, total and status.
Demo
River flat with a terrace
Lisbon, AlfamaBookingQX-48213Confirmed- Check-in
- · 15:00
- Check-out
- · 11:00
- Guests
- 2 adults, 1 child
- Change the booking
- Edit dates or guests
- 4 nights × €95
- €380.00
- Cleaning
- €40.00
- Weekly discount
- −€38.00
- Tourist tax€2 a night for each adult
- €16.00
- Total
- €398.00
Free cancellation until 1 November.
Pottery course
Awaiting payment- Starts
- Ends
- Guests
- 1 guest
- 1 session
- $45.00
- Total
- $45.00
Get it
It needs theme.qwe, as every component does; or take the whole kit, quillo-ui.qwe. Each component brings its own styles to the pages that show it.
$ curl -O https://quillolang.org/components/ui/theme.qwe$ curl -O https://quillolang.org/components/ui/booking_summary.qwemain.qwe
import ui/theme.qwe use theme_cssuse ui/booking_summary.qweroute GET / = <html><head><style>{theme_css}</style></head><body class="ui-root">...</body></html>Example
The code of the preview above.
demos/booking_summary.qwe
view BookingSummaryDemo() = <div.demo-row style="align-items: flex-start"> <div style="flex: 1 1 320px; max-width: 400px"> <BookingSummary id="booking-summary-demo-stay" title="River flat with a terrace" place="Lisbon, Alfama" image="https://picsum.photos/seed/flat/200/160" image_alt="A bright living room" check_in="2026-11-05" check_out="2026-11-09" times={{ in: "15:00", out: "11:00" }} guests="2 adults, 1 child" status="Confirmed" reference="QX-48213" edit_href="#booking_summary" lines={[{ label: "4 nights × €95", amount: "€380.00" }, { label: "Cleaning", amount: "€40.00" }, { label: "Weekly discount", amount: "−€38.00", tone: "success" }, { label: "Tourist tax", amount: "€16.00", hint: "€2 a night for each adult" }]} total="€398.00" note="Free cancellation until 1 November."/> </div> <div style="flex: 1 1 280px; max-width: 360px"> <BookingSummary id="booking-summary-demo-class" title="Pottery course" check_in="2026-11-02" check_out="2026-11-03" in_label="Starts" out_label="Ends" nights_label="session" guests={1} status="Awaiting payment" status_tone="warning" lines={[{ label: "1 session", amount: "$45.00" }]} total="$45.00"/> </div> </div>Source
ui/booking_summary.qwe
// BookingSummary: what was booked, for a checkout's side or a confirmation: the place// (with a picture), the dates in and out with the nights between, the guests, the price// line by line and the total, a status, and a note (the cancellation terms).//// <BookingSummary title="River flat" place="Lisbon, Alfama" image="/img/flat.jpg"// check_in="2026-11-05" check_out="2026-11-09" guests="2 adults, 1 child" status="Confirmed"// lines={[{ label: "4 nights × €95", amount: "€380.00" }, { label: "Cleaning", amount: "€40.00" },// { label: "Weekly discount", amount: "−€38.00", tone: "success" }]}// total="€382.00" note="Free cancellation until 1 November." edit_href="/booking/edit"/>//// title: what was booked; place: where; image: a picture (image_alt). check_in,// check_out: "YYYY-MM-DD", shown as "Thu 5 Nov 2026", with the nights between them// counted (nights_label: what a night is called, "night"; "session" for a class).// in_label ("Check-in"), out_label ("Check-out"). times: the hours, under the dates// ({ in: "15:00", out: "11:00" }). guests: text ("2 adults") or a number ("2 guests").// lines: a list of { label, amount, tone? ("success", "muted", "danger"), hint? }, the// amounts already written in their currency. total; total_label ("Total"). status: a// badge ("Confirmed"); status_tone: "success" (default), "warning", "danger", "info".// reference: the booking's code, shown and selectable. note: a small line at the end.// edit_href: an Edit link by the dates.import ui/theme.qwe use ui_clslet booking_summary_css = css`.ui-booking-summary { display: grid; gap: 14px; min-width: 0; padding: 16px; border: 1px solid var(--ui-border); border-radius: var(--ui-radius); background: var(--ui-surface); font: 14px/1.45 var(--ui-font); color: var(--ui-fg); --t: var(--ui-success); --ts: var(--ui-success-soft); }.ui-booking-summary-warning { --t: var(--ui-warning); --ts: var(--ui-warning-soft); }.ui-booking-summary-danger { --t: var(--ui-danger); --ts: var(--ui-danger-soft); }.ui-booking-summary-info { --t: var(--ui-info); --ts: var(--ui-info-soft); }.ui-booking-summary-head { display: flex; gap: 12px; align-items: flex-start; }.ui-booking-summary-head img { flex: none; width: 88px; height: 72px; border-radius: var(--ui-radius-sm); object-fit: cover; background: var(--ui-subtle); }.ui-booking-summary-what { display: grid; gap: 2px; min-width: 0; flex: 1; }.ui-booking-summary-title { margin: 0; font-size: 16px; font-weight: 650; line-height: 1.3; }.ui-booking-summary-place { color: var(--ui-muted); font-size: 13px; }.ui-booking-summary-status { justify-self: start; margin-top: 4px; padding: 2px 8px; border-radius: 999px; background: var(--ts); color: var(--t); font-size: 12px; font-weight: 600; }.ui-booking-summary-ref { color: var(--ui-muted); font-size: 12px; }.ui-booking-summary-ref code { font: 600 12px/1 var(--ui-mono); color: var(--ui-fg); user-select: all; }.ui-booking-summary-dates { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 8px; margin: 0; padding: 12px; border-radius: var(--ui-radius-sm); background: var(--ui-subtle); }.ui-booking-summary-dates div { display: grid; gap: 1px; min-width: 0; }.ui-booking-summary-dates div:last-child { text-align: right; }.ui-booking-summary-dates dt { color: var(--ui-muted); font-size: 12px; }.ui-booking-summary-dates dd { margin: 0; font-weight: 600; }.ui-booking-summary-dates small { color: var(--ui-muted); font-size: 12px; font-weight: 400; }.ui-booking-summary-nights { padding: 2px 8px; border: 1px solid var(--ui-border); border-radius: 999px; background: var(--ui-surface); color: var(--ui-muted); font-size: 12px; white-space: nowrap; }.ui-booking-summary-row { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }.ui-booking-summary-row dt { color: var(--ui-muted); }.ui-booking-summary-row dd { margin: 0; font-weight: 500; }.ui-booking-summary-facts { display: grid; gap: 6px; margin: 0; }.ui-booking-summary-edit { color: var(--ui-accent); font-size: 13px; text-decoration: none; }.ui-booking-summary-edit:hover { text-decoration: underline; }.ui-booking-summary-edit:focus-visible { outline: none; border-radius: 3px; box-shadow: var(--ui-focus); }.ui-booking-summary-lines { display: grid; gap: 6px; margin: 0; padding-top: 12px; border-top: 1px solid var(--ui-border); }.ui-booking-summary-line { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; }.ui-booking-summary-line dd { margin: 0; font-variant-numeric: tabular-nums; white-space: nowrap; }.ui-booking-summary-hint { display: block; color: var(--ui-muted); font-size: 12px; }.ui-booking-summary-success dt, .ui-booking-summary-success dd { color: var(--ui-success); }.ui-booking-summary-muted dt, .ui-booking-summary-muted dd { color: var(--ui-muted); }.ui-booking-summary-danger-line dt, .ui-booking-summary-danger-line dd { color: var(--ui-danger); }.ui-booking-summary-total { padding-top: 8px; border-top: 1px solid var(--ui-border); font-size: 16px; font-weight: 700; }.ui-booking-summary-note { margin: 0; color: var(--ui-muted); font-size: 12px; }`view BookingSummary(title: str, check_in: str, check_out: str, place: str? = null, image: str? = null, image_alt: str = "", guests = null, lines: list = [], total: str? = null, total_label: str = "Total", status: str? = null, status_tone: str = "success", reference: str? = null, note: str? = null, edit_href: str? = null, times: map? = null, in_label: str = "Check-in", out_label: str = "Check-out", nights_label: str = "night", id: str? = null, class: str? = null) { style global booking_summary_css let n = date.days_between(check_in, check_out) let who = guests == null ? null : (type_of(guests) == "int" ? `${guests} ${guests == 1 ? "guest" : "guests"}` : str(guests)) <section class={ui_cls(["ui-booking-summary", status_tone != "success" && `ui-booking-summary-${status_tone}`, class])} id={id} aria-label={`Booking: ${title}`}> <div.ui-booking-summary-head> {image != null && <img src={image} alt={image_alt} loading="lazy"/>} <div.ui-booking-summary-what> <h3.ui-booking-summary-title>{title}</h3> {place != null && <span.ui-booking-summary-place>{place}</span>} {reference != null && <span.ui-booking-summary-ref>Booking <code>{reference}</code></span>} {status != null && <span.ui-booking-summary-status>{status}</span>} </div> </div> <dl.ui-booking-summary-dates> <div> <dt>{in_label}</dt> <dd><time datetime={check_in}>{date.format(check_in, "ddd D MMM YYYY")}</time>{times != null && times.in != null && <small> · {times.in}</small>}</dd> </div> <span.ui-booking-summary-nights>{n} {n == 1 ? nights_label : `${nights_label}s`}</span> <div> <dt>{out_label}</dt> <dd><time datetime={check_out}>{date.format(check_out, "ddd D MMM YYYY")}</time>{times != null && times.out != null && <small> · {times.out}</small>}</dd> </div> </dl> {(who != null || edit_href != null) && <dl.ui-booking-summary-facts> {who != null && <div.ui-booking-summary-row><dt>Guests</dt><dd>{who}</dd></div>} {edit_href != null && <div.ui-booking-summary-row><dt><span.ui-sr>Change the booking</span></dt><dd><a.ui-booking-summary-edit href={edit_href}>Edit dates or guests</a></dd></div>} </dl>} {(len(lines) > 0 || total != null) && <dl.ui-booking-summary-lines> {for l in lines => <div key={l.label} class={ui_cls(["ui-booking-summary-line", l.tone == "success" && "ui-booking-summary-success", l.tone == "muted" && "ui-booking-summary-muted", l.tone == "danger" && "ui-booking-summary-danger-line"])}> <dt>{l.label}{l.hint != null && <span.ui-booking-summary-hint>{l.hint}</span>}</dt> <dd>{l.amount}</dd> </div>} {total != null && <div.ui-booking-summary-line.ui-booking-summary-total><dt>{total_label}</dt><dd>{total}</dd></div>} </dl>} {note != null && <p.ui-booking-summary-note>{note}</p>} </section>}Related
AddressCardA saved address with a Default badge and Edit and Remove, as submit buttons in a plain form or callbacks.6 views · 7 downloadsCartSummarySubtotal, shipping, tax, a discount and the total added up, with a Checkout button as a link, a form or a callback.6 views · 7 downloadsPaymentMethodsWays to pay as radio cards with their marks: card (with the brands taken), PayPal, Apple Pay, Google Pay, bank, cash.6 views · 6 downloadsPricingCardOne plan: name, price and period, what it includes, and a button; highlighted with a badge when it is the one to pick.7 views · 6 downloadsProductCardA product in a shop's grid: picture, name, price with the discount, stars, a badge and Add to cart, as a plain form or a callback.6 views · 6 downloadsProductGridProducts as ProductCards in a grid that fits as many across as there is room for, from a list of records.6 views · 5 downloads
Thread
Thread 0 posts
On BookingSummary: questions, tips, corrections, and code that uses it.
No posts yet. The first one opens the thread.