Build a Seat Booking System with Angular and Tailwindcss

By Ashik Basheer
2 min read

Table of Contents

Ever wondered how movie ticket booking sites let you choose your favorite seat?
In this tutorial, I’ll show you how to build a fully interactive seat selection UI using Angular and Tailwind CSS. This will be perfect for cinema apps, travel booking or event ticketing platforms.

HTML

<div class="flex h-full items-center justify-center gap-x-10 bg-linear-to-tr from-stone-100 to-stone-400">
  <!-- LHS -->
  <div class="flex flex-col gap-y-2">
    <h1 class="text-center font-bold text-3xl mb-4">Select your seat</h1>
    <!-- Layout -->
    <ng-container *ngFor="let row of layout">
      <ng-container *ngIf="!row.seat">
        <div class="flex h-12"></div>
      </ng-container>
      <div class="flex gap-x-2">
        <ng-container *ngFor="let seat of row.seat">
          <div
            (click)="updateSeat(seat)"
            *ngIf="seat.id"
            [ngClass]="{'!bg-gray-300 !cursor-not-allowed': seat.disabled, '!bg-stone-500 !text-white': seat.selected}"
               class="flex items-center justify-center w-10 h-10 border border-stone-500 rounded-md bg-stone-100 hover:bg-stone-300 cursor-pointer">
            {{seat.id}}
          </div>
          <div *ngIf="!seat.id" class="flex w-10 h-10">
          </div>
        </ng-container>
      </div>
    </ng-container>

  </div>

  <!-- RHS -->
  <div  *ngIf="selectedSeats.length" class="flex flex-col gap-y-2 border border-stone-500 rounded-md w-[200px] px-4 py-2">
    <h1 class="font-semibold">Booking Details</h1>
    <div class="flex justify-between">
      <span>Total Seats</span>
      <span>{{ selectedSeats.length }}</span>
    </div>
    <div class="flex justify-between border-t border-stone-500 pt-2">
      <span>Total Payable</span>
      <span>{{totalCost}}</span>
    </div>
  </div>
</div>

Data Logic

In the app.component.ts file add this "layout" property. Each object inside the array is a single row. The example shows seats for row A starting from A1 to A6. The object that has "id" as "null" is for the gap between seats.

layout: any[] = [
    {
      seat: [
        {
          id: "A1",
          type: "economy",
          price: 100,
          disabled: false
        },
        {
          id: "A2",
          type: "economy",
          price: 100,
          disabled: false
        },
        {
          id: "A3",
          type: "economy",
          price: 100,
          disabled: false
        },
        {
          id: null
        },
        {
          id: "A4",
          type: "economy",
          price: 100,
          disabled: false
        },
        {
          id: "A5",
          type: "economy",
          price: 100,
          disabled: false
        },
        {
          id: "A6",
          type: "economy",
          price: 100,
          disabled: false
        }
      ]
    }
]

Update seats and Calculate total cost

Each click on a seat is validated to be sure if a disabled seat is not toggled. Upon each selection the seat is added to a new array and the cost is calculated immediately.

updateSeat(seat: any) {
    if (seat.disabled) {
      return;
    }
    seat.selected = !seat.selected;
    if (seat.selected) {
      this.selectedSeats.push(seat);
    } else {
      this.selectedSeats = this.selectedSeats.filter((currentSeat: any) => currentSeat.id != seat.id)
    }
    this.calculatePrice();
  }

  calculatePrice() {
    let cost = 0;
    this.selectedSeats.map((seat: any) => {
      cost += seat.price;
    })
    this.totalCost = cost;
  }


Watch the full video, follow along and grab the source code from Github link.

Download source code from Github

Last Update: August 12, 2025

About the Author

Ashik Basheer Chennai, India

A passionate developer with 14+ years of experience building scalable enterprise apps and distributed systems. I thrive on simplifying real-world problems through open-source tech and engaging UX.

View All Posts