fine dining menu and reservations
A fine-dining front page built to make someone hungry in the first three seconds, then get them to a table booking without a phone call.
Demonstration build. Designed and built by me to show capability — not commissioned by a client. Everything you see is functional.
- Type
- Demonstration build
- Stack
- JS · Serverless API · Blobs
- Pages
- Single page, 7 sections
- Backend
- 5 endpoints
Recorded from the live build, desktop and phone · try it yourself ↗
Why I built it
Restaurants are one of the most common small-business requests I get, and most of them have the same two problems: the menu lives in a PDF that nobody opens on a phone, and bookings all arrive as WhatsApp messages at dinner rush. I built this to show what the fix looks like.
The menu is the product
The centrepiece is a filterable menu — appetisers, mains, desserts and drinks, switched with category buttons rather than a page reload. Each card fades out and back in as the filter changes, so the grid never jumps.
Eleven dishes are laid out as cards with descriptions and prices. On a phone the grid collapses to a single column and the cards stay legible at arm’s length, which is the actual reading condition in a restaurant.
Booking instead of phoning
A reservation form sits at the bottom of the page — date, time, party size, contact. It confirms in place rather than throwing the visitor to a new screen.
In this demonstration the form validates and confirms on the page but does not send anywhere, because there is no restaurant behind it. On a real build it would post to the booking inbox and send a confirmation.
Holding attention while you scroll
Sections reveal as they come into view using an IntersectionObserver rather than a scroll listener, so the effect costs almost nothing in performance.
The navigation highlights the section you are currently reading, tracked by a second observer. Small detail, but it stops long single-page sites from feeling like a void.
How it looks on a phone
Most of the people who will open a site like this are on a phone, on mobile data, standing up. Every layout here is checked down to 360px.
The backend
The booking form talks to a real reservations API. Seats are counted per seating, bookings persist, and the host sees them land on a live dashboard.
What the server does
- Counts covers per half-hour seating (24 seats each) and refuses a booking that would overfill it — offering the nearest times that still fit.
- Validates every field on the server; the browser checks are for convenience, not trust.
- Rate-limits bookings to 5 per 10 minutes per visitor, stored in Blobs so it holds across function instances.
- Gives each booking a code; look-up and cancel need the code and the email, and cancelling returns the seats.
- The host-stand view is PIN-protected and masks names, emails and phone numbers.
- seats left per seating
- book a table · try it on the demo
- look up (code + email) · try it on the demo
- cancel, frees the seats · try it on the demo
- host view (PIN, masked) · try it on the demo
// pick an endpoint marked GET/POST above to see the real response
The decisions behind it
No framework
30 KB of HTML, 27 KB of CSS, 12 KB of JavaScript. No build step, no dependency to update, nothing to break in two years.
Two observers, no scroll handlers
Reveal animations and active-link tracking both run on IntersectionObserver, which the browser optimises natively.
Dark by design
Fine dining reads as dark and warm. The palette is doing marketing work, not just decoration.
Other builds
Need one of these for real?
Tell me what the business does and who it is for. I will tell you what it costs and how long it takes — no charge for the conversation.