All websites

10 / Case study

Ambra Hotel & Spa / 2026

Ambra Hotel & Spa — booking where the price always adds up

A hotel demo in Astro and Sanity: a search with a price under every day, a room calendar, seasons and minimum stays set in the CMS. One function prices the whole site. On desktop, Lighthouse gives 100 in every category.

Role
Design and development / my own demo
Year
2026
Scope
  • Search and calendar
  • Seasonal rates
  • Room list
  • Leads in Sanity
  • Performance
Disciplines
  • Astro
  • Sanity
  • TypeScript
  • Cloudflare Workers
Visit site
The Ambra Hotel & Spa home page: the sea and the beach from above, the line “Dom nad samym morzem” (A home right by the sea) and the stay search

The idea

On a hotel’s site, a guest wants to know three things: is there a free room, how much will it cost, and how to book it. Ambra is a demo where those answers are there at every step, and the same everywhere.

It is a fictional boutique hotel in Sopot: six room types, a spa, a restaurant and events, in Polish and English. The pages are static HTML from Astro on Cloudflare Workers, and the content and prices are edited in Sanity.

The search on the first screen: a two-month calendar with the lowest price under every day and a stay of 16–18 November selected
The lowest nightly price under every day.

From the search to the room

The search shows two months, with the lowest nightly price and that season’s minimum stay under every day. The dates and the number of guests carry on: the room list shows each room’s price for the whole stay and its availability, and moves booked rooms to the end.

Rooms can be sorted (recommended, price, size, number of amenities) and filtered by amenities and guests. The choice is saved in the page address, so a result can be shared as a link.

The room list with sorting, the number of guests, a stay of 16–18 November and amenity filters
The room list knows the dates from the search.

The room calendar

On a room’s page, the calendar keeps the hotel’s rules: bookings from today up to a year ahead, at most 30 nights, the minimum stay of the arrival’s season, guests up to the room’s capacity. A stay can’t run through a booked night, but the departure day can be someone else’s arrival. Under the calendar, the number of nights, the nightly price and the total show at once.

The calendar follows the WAI-ARIA date picker pattern: one tab stop, the arrow keys, Home and End, PageUp and PageDown, and every day carries the full date and its price in its label. Without JavaScript, the room page shows the front desk’s phone number.

The Wydma room calendar with the nights of 16–18 November selected, prices under the days, booked days and a total of 1020 zł
Two nights at 510 zł: the total updates as dates are picked.

One price for the whole site

The rates live in Sanity: each room’s price, seasons with a multiplier and a minimum stay, and a surcharge for Friday and Saturday nights. The demo has four seasons, from low (×0.8) to the holidays (×1.5, at least 3 nights), and a weekend night costs 10% more.

One function sets the nightly price. The search, the room calendar, the rates table and the “from” prices on the list all use it, so a change in the CMS changes all four at once, and a guest never sees two different amounts for the same room.

Diagram: the rates in Sanity Studio (seasons, multipliers, minimum stays, the weekend surcharge) feed one nightly price function, and the same number reaches the search, the room calendar, the rates table and the “from” prices
One function, four places on the site.
The Rates page: seasons with dates and minimum stays, and a table of six rooms’ prices in four seasons
The rates table comes from the same data as the calendar.

What separates the demo from a live site

Ambra shows booking from the guest’s side, and the pricing engine. Its availability is simulated, and the “Book” button opens a summary instead of placing a booking; the page says so plainly.

The calendar asks about booked nights in one place, so in a real hotel the booking system answers there: a channel manager, a PMS, or a database of its own with a lock against double bookings. On top of that come the price checked again on the server, a deposit or payment, and an email confirmation.

Leads and performance

The newsletter and the contact form save into a separate, private dataset in Sanity, where the front desk sets their status and adds notes. Spam is kept out by a check of where the request came from, a hidden field, a minimum time to fill in the form and a limit of five sends a minute from one address. The forms also work without JavaScript.

The video on the first screen doesn’t slow the page: its still frame loads first (that is the LCP), and the film only after the page has loaded, never with data saving, a slow connection or reduced motion. The home page loads 6 KB of JavaScript.

Lighthouse on desktop (measured on 2 November 2026): 100 for performance, accessibility, best practices and SEO. In the mobile simulation, performance is 98 and the other categories 100.

Questions

  • Can you really book a room at Ambra?

    No, it is a demo: availability is simulated and no booking is placed. Prices, seasons and stay rules work as they would in a real hotel, though, and are edited in Sanity.

  • Can this connect to the system a hotel already uses?

    Usually yes, if the system has an API. The calendar asks about availability in one place, so the answer can come from a channel manager, a PMS or a database of its own. The server handles the booking and payment, with the price worked out again.

  • Who changes prices and seasons?

    The hotel, in Sanity Studio: each room’s price, season dates, the multiplier, minimum stays and the weekend surcharge. After publishing, the new prices are everywhere on the site.

Tell me what you need.

Reply within 24 h

What is it about?

Please enter your name.

Please enter a valid email address.

Please write a message (min. 10 characters).

Add details: company, timeline, budget
Budget optional

Form data is used only to reply to your message. Privacy policy

SR / Terminal

Tab completes · ↑↓ history · Esc closes