Learn how to create a time slot booking app using HTML, CSS, and JavaScript in this easy-to-follow guide. Build a functional and user-friendly booking system with simple steps.
Table of Contents
A time slot booking app is a valuable tool for managing appointments, reservations, and events. Whether you're scheduling meetings, classes, or any other time-sensitive activity, having an efficient system to book and manage time slots is essential. In this guide, we’ll walk you through the process of creating a simple and user-friendly time slot booking app using HTML, CSS, and JavaScript. You’ll learn how to set up the app, design the interface, and add functionality to allow users to choose a date, select a time slot, and confirm their booking.
Prerequisites:
Before we start, here are the things you should know:
- Basic understanding of HTML for creating the structure of the app.
- Basic knowledge of CSS for styling the app.
- Familiarity with JavaScript for adding interactivity to the app.
Source Code
Step 1 (HTML Code):
Start by creating the basic structure of the app using HTML. This includes creating a container for the time slots and a date picker to allow users to choose the date.
Here's a breakdown of the structure and functionality:
1. Document Structure
- DOCTYPE Declaration: Specifies the document type as HTML5 (
<!DOCTYPE html>
). - Language: The language of the document is set to English (
<html lang="en">
).
2. Head Section
- Character Set: Specifies the character encoding as UTF-8 (
<meta charset="UTF-8">
). - Viewport: Ensures the page is responsive on different devices (
<meta name="viewport" content="width=device-width, initial-scale=1.0">
). - Title: The title of the page is set to "Time Slot Booking App" (
<title>Time Slot Booking App</title>
). - Google Fonts: The Poppins font is linked for styling (
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600&display=swap" rel="stylesheet">
). - Stylesheet: The external CSS file (
styles.css
) is linked for styling the page (<link rel="stylesheet" href="styles.css">
).
3. Body Section
- Container: The main content is wrapped inside a
<div>
with the classcontainer
, which is used for layout and styling.
3.1. Heading
- The heading
<h1>
displays the title of the app: "Time Slot Booking App".
3.2. Date Picker
- A label (
<label for="booking-date">
) prompts the user to select a date. - An
<input>
field withtype="date"
allows the user to pick a date for booking.
3.3. Time Slot Container
- A
<div>
with the classtime-slot-container
will be populated dynamically with available time slots based on the selected date.
3.4. Booked Slots Table
- A section (
<div class="booked-slots-container">
) displays the booked slots in a table. - The table has three columns: Date, Time, and Status.
- The table body (
<tbody></tbody>
) will be dynamically populated with the booked slots.
4. Modals
- Confirmation Modal:
- This modal (
<div id="confirmation-modal" class="modal hidden">
) appears when the user selects a time slot to confirm the booking. - It contains a paragraph (
<p id="selected-slot"></p>
) to display the selected slot, and two buttons:- Confirm: A button (
<button id="confirm-btn" class="btn">Confirm</button>
) to confirm the booking. - Cancel: A button (
<button id="cancel-btn" class="btn cancel">Cancel</button>
) to close the modal without confirming.
- Confirm: A button (
- This modal (
- Cancel Booking Modal:
- This modal (
<div id="cancel-modal" class="modal hidden">
) appears when the user wants to cancel a booking. - It contains a message (
<p id="cancel-slot-message"></p>
) asking if they want to cancel the selected slot. - Two buttons are provided:
- Yes, Cancel: A button (
<button id="confirm-cancel-btn" class="btn cancel">Yes, Cancel</button>
) to confirm cancellation. - No: A button (
<button id="close-cancel-btn" class="btn">No</button>
) to close the modal without canceling.
- Yes, Cancel: A button (
- This modal (
5. External JavaScript
- The JavaScript file (
script.js
) is linked at the end of the body (<script src="script.js"></script>
), which will handle the logic for time slot selection, booking confirmation, and cancellation.
Step 2 (CSS Code):
Next, use CSS to make the app visually appealing. Here's a detailed explanation of the styles applied:
1. Body Styling
- Font: The body uses the
Poppins
font family, which is loaded from Google Fonts (font-family: 'Poppins', sans-serif
). - Margin and Padding: The default margin and padding are removed (
margin: 0; padding: 0;
). - Background and Text Color: The background color is set to a purple shade (
background: #825CFF;
) and the text color to dark gray (color: #333;
). - Flexbox Layout: The body uses flexbox to center the content both horizontally and vertically (
display: flex; justify-content: center; align-items: center;
).
2. Container Styling
- Width and Max-Width: The container has a width of 90% of the viewport and a maximum width of 500px (
width: 90%; max-width: 500px;
). - Background and Padding: The background is white (
background: #fff;
), with padding around the content (padding: 25px;
). - Margin and Border Radius: A margin of 30px is applied on the top and bottom, with auto left and right margins for centering. The container has rounded corners (
border-radius: 12px;
). - Box Shadow: A subtle shadow is applied to the container for depth (
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
). - Text Alignment: The text inside the container is centered (
text-align: center;
).
3. Heading Styling (h1)
- Margin and Font Size: A margin of 20px is added at the bottom of the heading (
margin-bottom: 20px;
), and the font size is set to 28px (font-size: 28px;
). - Text Color: The text color is dark gray (
color: #333;
).
4. Time Slot Container
- Flex Layout: The container for the time slots uses flexbox with wrapping and spacing between items (
display: flex; flex-wrap: wrap; gap: 12px; justify-content: center;
).
5. Time Slot Styling
- Padding and Background: Each time slot has padding (
padding: 12px 18px;
), rounded corners (border-radius: 8px;
), and a light blue background (background: #e0e7ff;
). - Text Color: The text color is dark gray (
color: #333;
). - Cursor: The cursor changes to a pointer to indicate that the element is clickable (
cursor: pointer;
). - Transition: A smooth transition effect is applied for background color and scaling (
transition: background 0.3s, transform 0.2s;
). - Hover Effect: When hovered, the background color changes to a lighter blue (
background: #c7d2fe;
), and the slot scales up slightly (transform: scale(1.05);
).
6. Booked Time Slot Styling
- Booked Slots: Time slots that are booked have a red background (
background: #ffd6d6;
) and red text (color: #b91c1c;
). The cursor is set tonot-allowed
, indicating that the slot cannot be clicked.
7. Selected Time Slot Styling
- Selected Slots: When a time slot is selected, the background changes to the main purple color (
background: #825CFF;
) and the text becomes white (color: #fff;
).
8. Booked Slots Table Styling
- Container: The booked slots table is inside a container with a margin on top (
margin-top: 30px;
), and the text is aligned to the left. - Table Layout: The table is styled to take up the full width (
width: 100%
), and the borders collapse into a single line (border-collapse: collapse;
). - Table Headers and Cells: Padding is applied to both table headers (
th
) and cells (td
), and borders are added (border: 1px solid #ccc;
). - Header Styling: The header row has a purple background (
background-color: #825CFF;
) and white text (color: white;
). - Booked and Available Slot Styling: The booked slots are highlighted with a light red background (
background-color: #ffd6d6;
) and red text (color: #b91c1c;
). Available slots are styled with a light blue background (background-color: #e0e7ff;
).
9. Modal Styling
- Modal Layout: The modal is fixed to the top-left corner of the viewport and takes up the entire screen (
position: fixed; top: 0; left: 0; width: 100%; height: 100%;
), with a semi-transparent black background (background: rgba(0, 0, 0, 0.5);
). - Centering Modal: Flexbox is used to center the modal content (
display: flex; justify-content: center; align-items: center;
). - Hidden Class: The modal is hidden by default (
display: none;
) using thehidden
class. - Modal Content: The modal content has a white background, padding, rounded corners, and a maximum width of 400px (
max-width: 400px;
), with text centered (text-align: center;
).
10. Button Styling
- General Button Styling: Buttons have padding, rounded corners, and a purple background (
background: #825CFF;
), with white text (color: #fff;
). - Cancel Button: Buttons with the
cancel
class have a red background (background: #ff6b6b;
). - Hover Effect: The opacity of buttons decreases slightly when hovered (
opacity: 0.9;
).
11. Tooltip for Time Slots
- Tooltip: Time slots that have a
data-tooltip
attribute will show a tooltip on hover. The tooltip is positioned above the time slot (top: -30px;
), with a dark background (background: #333;
), white text, and padding. - Positioning: The tooltip is displayed using the
::after
pseudo-element, which is triggered on hover.
12. Date Picker Styling
- Container: The date picker has a margin at the bottom (
margin-bottom: 20px;
). - Label: The label for the date picker has a font size of 16px and a margin to the right (
margin-right: 10px;
). - Input Field: The input field for the date picker has padding, rounded corners, and a border. The font size is set to 14px.
body {
font-family: 'Poppins', sans-serif;
margin: 0;
padding: 0;
background: #825CFF;
color: #333;
display: flex;
justify-content: center;
align-items: center;
}
.container {
width: 90%;
max-width: 500px;
background: #fff;
padding: 25px;
margin: 30px auto;
border-radius: 12px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
text-align: center;
}
h1 {
margin-bottom: 20px;
font-size: 28px;
color: #333;
}
.time-slot-container {
display: flex;
flex-wrap: wrap;
gap: 12px;
justify-content: center;
}
.time-slot {
padding: 12px 18px;
border-radius: 8px;
background: #e0e7ff;
color: #333;
cursor: pointer;
transition: background 0.3s, transform 0.2s;
font-size: 14px;
}
.time-slot:hover {
background: #c7d2fe;
transform: scale(1.05);
}
.time-slot.booked {
background: #ffd6d6;
color: #b91c1c;
cursor: not-allowed;
}
.time-slot.selected {
background: #825CFF;
color: #fff;
}
.booked-slots-container {
margin-top: 30px;
text-align: left;
}
.booked-slots-container table {
width: 100%;
border-collapse: collapse;
}
.booked-slots-container th, .booked-slots-container td {
padding: 12px;
border: 1px solid #ccc;
}
.booked-slots-container th {
background-color: #825CFF;
color: white;
}
.booked-slots-container .booked {
background-color: #ffd6d6;
color: #b91c1c;
}
.booked-slots-container .available {
background-color: #e0e7ff;
color: #333;
}
.modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
}
.modal.hidden {
display: none;
}
.modal-content {
background: #fff;
padding: 20px;
border-radius: 10px;
width: 90%;
max-width: 400px;
text-align: center;
}
.btn {
font-family: 'Poppins', sans-serif;
padding: 10px 20px;
margin: 10px;
border: none;
border-radius: 8px;
cursor: pointer;
font-size: 16px;
color: #fff;
background: #825CFF;
}
.btn.cancel {
background: #ff6b6b;
}
.btn:hover {
opacity: 0.9;
}
.time-slot[data-tooltip]:hover::after {
content: attr(data-tooltip);
position: absolute;
background: #333;
color: #fff;
padding: 5px 10px;
border-radius: 5px;
font-size: 12px;
top: -30px;
white-space: nowrap;
}
.date-picker {
margin-bottom: 20px;
}
.date-picker label {
font-size: 16px;
margin-right: 10px;
}
.date-picker input {
font-family: 'Poppins', sans-serif;
padding: 8px 10px;
border-radius: 6px;
border: 1px solid #ccc;
font-size: 14px;
}
Step 3 (JavaScript Code):
Now, let's add the functionality using JavaScript. This will allow users to select a time slot, confirm the booking, and display the confirmation modal. Here's a breakdown of the functionality:
- Event Listener on DOMContentLoaded:
- The code listens for the
DOMContentLoaded
event to ensure the DOM is fully loaded before executing the script.
- The code listens for the
- Variables:
- Various DOM elements are selected and stored in variables such as
bookedSlotsTableBody
,timeSlotContainer
,modal
,cancelModal
, and buttons for confirming or canceling bookings. - The
timeSlots
array contains the available time slots for booking. bookings
holds the booking data, which is stored inlocalStorage
and parsed as a JSON object.
- Various DOM elements are selected and stored in variables such as
- Rendering Time Slots:
- The
renderTimeSlots(date)
function creates and displays the available time slots for a selected date. - If a time slot is already booked, it is marked as "Booked" and cannot be selected. A tooltip is displayed to indicate whether the slot is available or booked.
- If a slot is available, clicking it will select the slot and show a confirmation modal.
- Booked slots are clickable to prompt a cancelation modal.
- The
- Rendering the Bookings Table:
- The
renderTable()
function updates a table that displays all the booked slots frombookings
. If there are no bookings, a message is displayed.
- The
- Selecting a Slot:
- The
selectSlot(slot, element)
function is triggered when an available time slot is clicked. It ensures that a date is selected before allowing slot selection. The selected slot is highlighted, and a modal is shown for confirmation.
- The
- Booking Confirmation:
- When the "Confirm" button is clicked, the selected slot is added to the
bookings
object, and the updated bookings are saved tolocalStorage
. A confirmation message is shown, and the modal is hidden.
- When the "Confirm" button is clicked, the selected slot is added to the
- Canceling a Booking:
- The
promptCancel(slot)
function is triggered when a booked slot is clicked, asking the user if they want to cancel the booking. - If confirmed, the selected slot is removed from the
bookings
object, and the updated bookings are saved. A message confirms the cancellation.
- The
- Date Picker:
- The
datePicker
listens for changes to the date input and updates the selected date. If the date is valid, the available time slots for that date are rendered.
- The
- Modal and Cancel Modal:
- The modals for confirming bookings and canceling bookings are toggled using the
hidden
class. When the user interacts with the modals (confirming or canceling), the relevant actions are performed, and the UI is updated.
- The modals for confirming bookings and canceling bookings are toggled using the
- LocalStorage:
- The booking data is stored in
localStorage
to persist across page reloads. When a booking is confirmed or canceled, the data is updated and saved back tolocalStorage
.
document.addEventListener("DOMContentLoaded", () => {
const bookedSlotsTableBody = document.querySelector("#booked-slots-table tbody");
const timeSlotContainer = document.querySelector(".time-slot-container");
const modal = document.getElementById("confirmation-modal");
const cancelModal = document.getElementById("cancel-modal");
const selectedSlotDisplay = document.getElementById("selected-slot");
const cancelSlotMessage = document.getElementById("cancel-slot-message");
const confirmBtn = document.getElementById("confirm-btn");
const cancelBtn = document.getElementById("cancel-btn");
const confirmCancelBtn = document.getElementById("confirm-cancel-btn");
const closeCancelBtn = document.getElementById("close-cancel-btn");
const datePicker = document.getElementById("booking-date");
const timeSlots = [
"9:00 AM", "9:30 AM", "10:00 AM", "10:30 AM",
"11:00 AM", "11:30 AM", "12:00 PM", "12:30 PM",
"1:00 PM", "1:30 PM", "2:00 PM", "2:30 PM",
"3:00 PM", "3:30 PM", "4:00 PM", "4:30 PM",
];
let bookings = JSON.parse(localStorage.getItem("bookings")) || {};
let selectedSlot = null;
let selectedDate = null;
function renderTimeSlots(date) {
timeSlotContainer.innerHTML = "";
const bookedSlots = bookings[date] || [];
renderTable();
timeSlots.forEach((slot) => {
const slotDiv = document.createElement("div");
slotDiv.classList.add("time-slot");
slotDiv.setAttribute(
"data-tooltip",
bookedSlots.includes(slot) ? "Booked" : "Available"
);
if (bookedSlots.includes(slot)) {
slotDiv.classList.add("booked");
slotDiv.textContent = `${slot} (Booked)`;
slotDiv.addEventListener("click", () => promptCancel(slot));
} else {
slotDiv.textContent = slot;
slotDiv.addEventListener("click", () => selectSlot(slot, slotDiv));
}
timeSlotContainer.appendChild(slotDiv);
});
}
function renderTable() {
bookedSlotsTableBody.innerHTML = "";
if (Object.keys(bookings).length === 0) {
const noBookingsRow = document.createElement("tr");
const noBookingsCell = document.createElement("td");
noBookingsCell.colSpan = 4;
noBookingsCell.textContent = "No bookings available.";
noBookingsRow.appendChild(noBookingsCell);
bookedSlotsTableBody.appendChild(noBookingsRow);
return;
}
Object.keys(bookings).forEach((date) => {
const bookedSlots = bookings[date];
bookedSlots.forEach((slot) => {
const row = document.createElement("tr");
const dateCell = document.createElement("td");
dateCell.textContent = date;
row.appendChild(dateCell);
const slotCell = document.createElement("td");
slotCell.textContent = slot;
row.appendChild(slotCell);
const statusCell = document.createElement("td");
statusCell.textContent = "Booked";
row.appendChild(statusCell);
bookedSlotsTableBody.appendChild(row);
});
});
}
function selectSlot(slot, element) {
if (!selectedDate) {
alert("Please select a date first.");
return;
}
document.querySelectorAll(".time-slot").forEach((slotEl) => {
slotEl.classList.remove("selected");
});
element.classList.add("selected");
selectedSlot = slot;
showModal(slot);
}
function showModal(slot) {
selectedSlotDisplay.textContent = `You selected: ${slot} on ${selectedDate}`;
modal.classList.remove("hidden");
}
function promptCancel(slot) {
selectedSlot = slot;
cancelSlotMessage.textContent = `Do you want to cancel booking for ${slot} on ${selectedDate}?`;
cancelModal.classList.remove("hidden");
}
confirmBtn.addEventListener("click", () => {
if (selectedSlot) {
if (!bookings[selectedDate]) bookings[selectedDate] = [];
bookings[selectedDate].push(selectedSlot);
localStorage.setItem("bookings", JSON.stringify(bookings)); // Save bookings to localStorage
alert(`Booking confirmed for ${selectedSlot} on ${selectedDate}!`);
modal.classList.add("hidden");
renderTimeSlots(selectedDate);
}
});
cancelBtn.addEventListener("click", () => {
modal.classList.add("hidden");
});
confirmCancelBtn.addEventListener("click", () => {
const index = bookings[selectedDate].indexOf(selectedSlot);
if (index > -1) {
bookings[selectedDate].splice(index, 1);
localStorage.setItem("bookings", JSON.stringify(bookings)); // Save updated bookings to localStorage
alert(`Booking for ${selectedSlot} on ${selectedDate} has been canceled.`);
cancelModal.classList.add("hidden");
renderTimeSlots(selectedDate);
}
});
closeCancelBtn.addEventListener("click", () => {
cancelModal.classList.add("hidden");
});
datePicker.addEventListener("change", (e) => {
selectedDate = e.target.value;
if (!selectedDate) {
alert("Please select a valid date.");
return;
}
renderTimeSlots(selectedDate);
});
renderTimeSlots(selectedDate);
});
Final Output:
Conclusion:
By following this tutorial, you've learned how to create a functional time slot booking app from scratch using just HTML, CSS, and JavaScript. This app provides a simple yet effective way for users to schedule appointments or reserve time slots. With this foundation, you can further enhance the app by adding more features, such as saving bookings to a database or integrating advanced functionalities. This project is a great way to improve your web development skills while building something practical and easy to use.
That’s a wrap!
I hope you enjoyed this post. Now, with these examples, you can create your own amazing page.
Did you like it? Let me know in the comments below 🔥 and you can support me by buying me a coffee
And don’t forget to sign up to our email newsletter so you can get useful content like this sent right to your inbox!
Thanks!
Faraz 😊