About this snippet

A fully functional cinema booking UI. Users can select available seats, skip occupied ones, and see a real-time price calculation. Features a 3D screen effect, native SVG icons, and efficient JavaScript event delegation.

Size
6.3 KB
Uses
HTML, CSS, JavaScript
Loads
Nothing external
Views
437
<div class="cinema-wrapper">
  <div class="screen-container">
    <div class="screen"></div>
  </div>
  
  <ul class="legend">
    <li>
      <div class="seat-sample"></div>
      <small>Available</small>
    </li>
    <li>
      <div class="seat-sample selected"></div>
      <small>Selected</small>
    </li>
    <li>
      <div class="seat-sample occupied"></div>
      <small>Occupied</small>
    </li>
  </ul>

  <div class="seat-grid">
    <!-- Row 1 -->
    <svg class="seat" viewBox="0 0 24 24"><path d="M4 18v3h3v-3h10v3h3v-6H4zm15-8h3v5h-3V10zM2 10h3v5H2V10zm3-6h14c1.1 0 2 .9 2 2v2H3V6c0-1.1.9-2 2-2z"></path></svg>
    <svg class="seat" viewBox="0 0 24 24"><path d="M4 18v3h3v-3h10v3h3v-6H4zm15-8h3v5h-3V10zM2 10h3v5H2V10zm3-6h14c1.1 0 2 .9 2 2v2H3V6c0-1.1.9-2 2-2z"></path></svg>
    <svg class="seat" viewBox="0 0 24 24"><path d="M4 18v3h3v-3h10v3h3v-6H4zm15-8h3v5h-3V10zM2 10h3v5H2V10zm3-6h14c1.1 0 2 .9 2 2v2H3V6c0-1.1.9-2 2-2z"></path></svg>
    <svg class="seat" viewBox="0 0 24 24"><path d="M4 18v3h3v-3h10v3h3v-6H4zm15-8h3v5h-3V10zM2 10h3v5H2V10zm3-6h14c1.1 0 2 .9 2 2v2H3V6c0-1.1.9-2 2-2z"></path></svg>
    <svg class="seat" viewBox="0 0 24 24"><path d="M4 18v3h3v-3h10v3h3v-6H4zm15-8h3v5h-3V10zM2 10h3v5H2V10zm3-6h14c1.1 0 2 .9 2 2v2H3V6c0-1.1.9-2 2-2z"></path></svg>
    <svg class="seat" viewBox="0 0 24 24"><path d="M4 18v3h3v-3h10v3h3v-6H4zm15-8h3v5h-3V10zM2 10h3v5H2V10zm3-6h14c1.1 0 2 .9 2 2v2H3V6c0-1.1.9-2 2-2z"></path></svg>
    
    <!-- Row 2 -->
    <svg class="seat" viewBox="0 0 24 24"><path d="M4 18v3h3v-3h10v3h3v-6H4zm15-8h3v5h-3V10zM2 10h3v5H2V10zm3-6h14c1.1 0 2 .9 2 2v2H3V6c0-1.1.9-2 2-2z"></path></svg>
    <svg class="seat occupied" viewBox="0 0 24 24"><path d="M4 18v3h3v-3h10v3h3v-6H4zm15-8h3v5h-3V10zM2 10h3v5H2V10zm3-6h14c1.1 0 2 .9 2 2v2H3V6c0-1.1.9-2 2-2z"></path></svg>
    <svg class="seat occupied" viewBox="0 0 24 24"><path d="M4 18v3h3v-3h10v3h3v-6H4zm15-8h3v5h-3V10zM2 10h3v5H2V10zm3-6h14c1.1 0 2 .9 2 2v2H3V6c0-1.1.9-2 2-2z"></path></svg>
    <svg class="seat" viewBox="0 0 24 24"><path d="M4 18v3h3v-3h10v3h3v-6H4zm15-8h3v5h-3V10zM2 10h3v5H2V10zm3-6h14c1.1 0 2 .9 2 2v2H3V6c0-1.1.9-2 2-2z"></path></svg>
    <svg class="seat" viewBox="0 0 24 24"><path d="M4 18v3h3v-3h10v3h3v-6H4zm15-8h3v5h-3V10zM2 10h3v5H2V10zm3-6h14c1.1 0 2 .9 2 2v2H3V6c0-1.1.9-2 2-2z"></path></svg>
    <svg class="seat" viewBox="0 0 24 24"><path d="M4 18v3h3v-3h10v3h3v-6H4zm15-8h3v5h-3V10zM2 10h3v5H2V10zm3-6h14c1.1 0 2 .9 2 2v2H3V6c0-1.1.9-2 2-2z"></path></svg>

    <!-- Row 3 -->
    <svg class="seat" viewBox="0 0 24 24"><path d="M4 18v3h3v-3h10v3h3v-6H4zm15-8h3v5h-3V10zM2 10h3v5H2V10zm3-6h14c1.1 0 2 .9 2 2v2H3V6c0-1.1.9-2 2-2z"></path></svg>
    <svg class="seat" viewBox="0 0 24 24"><path d="M4 18v3h3v-3h10v3h3v-6H4zm15-8h3v5h-3V10zM2 10h3v5H2V10zm3-6h14c1.1 0 2 .9 2 2v2H3V6c0-1.1.9-2 2-2z"></path></svg>
    <svg class="seat" viewBox="0 0 24 24"><path d="M4 18v3h3v-3h10v3h3v-6H4zm15-8h3v5h-3V10zM2 10h3v5H2V10zm3-6h14c1.1 0 2 .9 2 2v2H3V6c0-1.1.9-2 2-2z"></path></svg>
    <svg class="seat" viewBox="0 0 24 24"><path d="M4 18v3h3v-3h10v3h3v-6H4zm15-8h3v5h-3V10zM2 10h3v5H2V10zm3-6h14c1.1 0 2 .9 2 2v2H3V6c0-1.1.9-2 2-2z"></path></svg>
    <svg class="seat occupied" viewBox="0 0 24 24"><path d="M4 18v3h3v-3h10v3h3v-6H4zm15-8h3v5h-3V10zM2 10h3v5H2V10zm3-6h14c1.1 0 2 .9 2 2v2H3V6c0-1.1.9-2 2-2z"></path></svg>
    <svg class="seat occupied" viewBox="0 0 24 24"><path d="M4 18v3h3v-3h10v3h3v-6H4zm15-8h3v5h-3V10zM2 10h3v5H2V10zm3-6h14c1.1 0 2 .9 2 2v2H3V6c0-1.1.9-2 2-2z"></path></svg>
  </div>

  <p class="text">
    You have selected <span id="count">0</span> seats for a total of $<span id="total">0</span>
  </p>
</div>
* { box-sizing: border-box; }
body {
  font-family: system-ui, "Segoe UI", sans-serif;
  background: #1e1e24; /* Dark cinema background */
  color: #fff;
  height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.cinema-wrapper {
  perspective: 1000px; /* Essential for 3D effect */
  display: flex;
  flex-direction: column;
  align-items: center;
}

.screen-container {
  margin-bottom: 30px;
}

.screen {
  background: #fff;
  height: 70px;
  width: 250px;
  margin: 15px 0;
  transform: rotateX(-45deg); /* 3D tilt */
  box-shadow: 0 3px 10px rgba(255, 255, 255, 0.75);
}

.legend {
  background: rgba(0, 0, 0, 0.2);
  padding: 10px 20px;
  border-radius: 6px;
  display: flex;
  justify-content: center;
  gap: 20px;
  list-style-type: none;
  margin-bottom: 20px;
}

.legend li {
  display: flex;
  align-items: center;
  gap: 8px;
}

.legend small {
  color: #94a3b8;
}

.seat-sample {
  height: 20px;
  width: 20px;
  background: #444451;
  border-top-left-radius: 10px;
  border-top-right-radius: 10px;
}

.seat-sample.selected { background: #3b82f6; }
.seat-sample.occupied { background: #ef4444; }

.seat-grid {
  display: grid;
  grid-template-columns: repeat(6, auto); /* 6 seats per row */
  column-gap: 12px;
  row-gap: 16px;
  margin-bottom: 30px;
}

/* SVG Seat Styling */
.seat {
  width: 32px;
  height: 32px;
  fill: #444451; /* Default available color */
  cursor: pointer;
  transition: transform 0.2s, fill 0.2s;
}

/* Row grouping logic: Adding space between 2nd and 3rd seat for aisle */
.seat:nth-of-type(6n+2) {
  margin-right: 18px;
}
.seat:nth-of-type(6n+4) {
  margin-right: 18px;
}

.seat:not(.occupied):hover {
  transform: scale(1.2);
  fill: #666;
}

.seat.selected {
  fill: #3b82f6; /* Blue */
}

.seat.occupied {
  fill: #ef4444; /* Red */
  cursor: not-allowed;
  transform: scale(1);
}

.text {
  color: #cbd5e1;
  font-size: 1.1rem;
}

span {
  color: #3b82f6;
  font-weight: 700;
}
const container = document.querySelector(".seat-grid");
const count = document.getElementById("count");
const total = document.getElementById("total");
const ticketPrice = 12; // Price per seat

// Event Delegation: Listen for clicks on the container
container.addEventListener("click", (e) => {
  // Check if target is a seat and NOT occupied
  // Note: e.target might be the path, so we use closest() to find the SVG
  const seat = e.target.closest(".seat");

  if (seat && !seat.classList.contains("occupied")) {
    seat.classList.toggle("selected");
    updateSelectedCount();
  }
});

function updateSelectedCount() {
  const selectedSeats = document.querySelectorAll(".seat-grid .seat.selected");
  const selectedSeatsCount = selectedSeats.length;

  count.innerText = selectedSeatsCount;
  total.innerText = selectedSeatsCount * ticketPrice;
}
Esc
↑↓ moveEnter select

Start from a template

Open an .html file, or HTML, CSS, JS, Markdown, Less or TypeScript files. You can also drop them here. Styles and scripts go into their panes.

Share

Source

Keyboard shortcuts

Save