webdevpuneet.com

Restaurant Table Reservation Form — Free Booking Form Snippet

Restaurant Table Reservation Form · Forms · Plain HTML, CSS & JS · Live preview

CategoryForms

Copy & paste

Source Code

<div class="trf-wrap">
  <form class="trf-form" id="trfForm">
    <h2 class="trf-heading">Reserve a table</h2>

    <div class="trf-field">
      <span class="trf-label">Party size</span>
      <div class="trf-stepper">
        <button type="button" class="trf-step-btn" id="trfMinus" aria-label="Decrease guests">−</button>
        <span class="trf-guests-value" id="trfGuests">2</span>
        <span class="trf-guests-suffix">guests</span>
        <button type="button" class="trf-step-btn" id="trfPlus" aria-label="Increase guests">+</button>
      </div>
    </div>

    <div class="trf-field">
      <label class="trf-label" for="trfDate">Date</label>
      <input class="trf-date" type="date" id="trfDate" name="date" required />
    </div>

    <div class="trf-field">
      <span class="trf-label">Time</span>
      <div class="trf-slots" id="trfSlots" role="radiogroup" aria-label="Reservation time">
        <button type="button" class="trf-slot" data-time="5:30 PM">5:30 PM</button>
        <button type="button" class="trf-slot" data-time="6:00 PM">6:00 PM</button>
        <button type="button" class="trf-slot" data-full="true" data-time="6:30 PM" disabled>6:30 PM</button>
        <button type="button" class="trf-slot" data-time="7:00 PM">7:00 PM</button>
        <button type="button" class="trf-slot" data-full="true" data-time="7:30 PM" disabled>7:30 PM</button>
        <button type="button" class="trf-slot" data-time="8:00 PM">8:00 PM</button>
        <button type="button" class="trf-slot" data-time="8:30 PM">8:30 PM</button>
        <button type="button" class="trf-slot" data-time="9:00 PM">9:00 PM</button>
      </div>
    </div>

    <div class="trf-field">
      <label class="trf-label" for="trfName">Name</label>
      <input class="trf-input" type="text" id="trfName" name="name" placeholder="Jordan Lee" required />
    </div>

    <button type="submit" class="trf-submit" id="trfSubmit" disabled>Confirm reservation</button>
  </form>

  <div class="trf-confirm" id="trfConfirm" hidden>
    <span class="trf-confirm-icon" aria-hidden="true">✓</span>
    <h2 class="trf-confirm-title">Table confirmed</h2>
    <div class="trf-confirm-row"><span>Name</span><strong id="trfSumName"></strong></div>
    <div class="trf-confirm-row"><span>Party</span><strong id="trfSumGuests"></strong></div>
    <div class="trf-confirm-row"><span>Date</span><strong id="trfSumDate"></strong></div>
    <div class="trf-confirm-row"><span>Time</span><strong id="trfSumTime"></strong></div>
    <button type="button" class="trf-new" id="trfNew">Book another table</button>
  </div>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month, 7 days free), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Party-size stepper
Clamped +/- control instead of a number input.
Native date input
Browser-native accessible date picker.
Slot grid with full states
Disabled, struck-through slots read as unavailable.
Single-select time toggle
aria-pressed enforces one active slot.
Gated submit button
Disabled until every field validates.
Confirmation summary card
Formatted date, party, time recap the booking.
Full reset flow
One button restores form and clears all state.
Zero dependencies
Plain HTML, CSS, and JS, no CDN.

About this UI Snippet

Restaurant Table Reservation Form — Party Size, Date, Slots, Confirmation

Screenshot of the Restaurant Table Reservation Form snippet rendered live

The table reservation form is the booking widget restaurant sites use to take a reservation in one screen — how many guests, which date, which time slot, and a name — before flipping to a confirmation summary. This snippet builds the whole flow in plain HTML, CSS, and JavaScript, no dependencies.

A stepper instead of a number input

Party size uses two buttons around a live count rather than a native <input type="number">, which is easier to tap on mobile and lets you clamp the range (1 to 12 here) with disabled states at each bound rather than relying on min/max validation messages that vary across browsers.

Time slots as a button grid, some disabled

Times render as a grid of toggle buttons rather than a <select>, so the full state is visible at a glance — full slots carry disabled plus data-full="true" and get a struck-through, dimmed style, while open slots toggle an aria-pressed state on click. Only one slot can be selected at a time; clicking a new one clears the previous aria-pressed flag first.

Validation gates the submit button

The confirm button starts disabled and validate() re-checks after every relevant change — date filled, a time slot chosen, a name typed — enabling the button only once all three are satisfied. This gives instant feedback without a separate error-message pass, appropriate for a short form like this one.

A real confirmation state, not just a toast

Submitting swaps the form out (hidden) for a confirmation card summarizing name, party size, formatted date, and time — mirroring what a real booking flow does before emailing a receipt. A "Book another table" button resets every piece of state (stepper, slots, form fields, disabled submit) and swaps back to the form.

Accessible by default

The time slot grid uses role="radiogroup" semantics via aria-pressed toggle buttons, guest stepper buttons carry aria-labels, and the date field is a native <input type="date"> so it gets the browser's own accessible date picker rather than a custom-built one.

Customizing it

Wire the slots to a real availability API, add a party-size cap per time slot, or add a special-requests textarea. Pair it with a time slot picker, availability scheduler, or date picker for related booking patterns.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSA reservation form with stepper, date, and slots renders.
  2. 2
    Adjust party size+/- buttons clamp between 1 and 12 guests.
  3. 3
    Pick a date and timeFull slots are disabled and struck through.
  4. 4
    Type a nameThe submit button enables once all fields are valid.
  5. 5
    Submit the formA confirmation card summarizes the booking.
  6. 6
    Book againThe reset button restores the form to its initial state.

Real-world uses

Common Use Cases

Restaurant booking pages
Take a reservation in one screen using a party-size stepper, native date input and a grid of time slots, beside a menu item customizer for pre-orders.
Booking platform siblings
Compare with a standalone time slot picker when only the time grid is needed without guest numbers.
Salon and spa appointments
Reuse the slot grid for appointments, with full slots disabled and struck through so people never click something unavailable.
Event RSVP adaptation
Adapt guests and slots into an RSVP form, using aria-pressed to ensure only one time is ever selected.
Coworking and small business booking
Book a room or desk with the same grid, as a lightweight alternative to a full booking system for a small business site.

Got questions?

Frequently Asked Questions

Full slot buttons carry both the disabled attribute and a data-full="true" flag, and CSS applies reduced opacity plus a struck-through text style when disabled. Because they're genuinely disabled buttons, they can't receive focus or clicks, so users can't accidentally select an unavailable time.

Each slot click handler first clears aria-pressed="false" on every slot, then sets aria-pressed="true" on the clicked one and records its time in a selectedTime variable — giving single-select toggle-button behavior without native radio inputs.

A validate() function runs after every relevant input (date change, slot click, name typed) and checks that selectedTime, the date value, and a non-empty trimmed name are all present, only then removing the disabled attribute from the submit button.

The form's submit handler prevents the default page reload, populates the confirmation card's summary fields (name, formatted party size, a human-readable date via toLocaleDateString, and the selected time), then hides the form and shows the confirmation view.

Render the slot buttons from your availability API response, marking any slot the API reports as full with the disabled attribute and data-full="true" instead of hardcoding it, and keep the same click handler logic for selection.