Published OnApril 1, 2025November 22, 2023

Building an airline seat map in SwiftUI

I've been asked to do a tutorial about building an airline seat map in SwiftUI many times. This has been my go-to snippet for years! It's super customizable and provides an awesome starter for any iOS developer in aviation.

If you've ever booked a flight, you're familiar with the seat map where you choose your preferred seat. In this tutorial, we'll replicate this feature using SwiftUI.

Step 1: Define the Data Model

Let's start by defining our data model:

enum SeatState {
    case empty
    case occupied
}

struct SeatId: Equatable, Hashable {
    var row: Int
    var letter: String
}

struct Seat: Identifiable, Equatable {
    var id: SeatId
    var state: SeatState
}

Here, each Seat has an id (consisting of its row and letter) and a state (which can be either empty or occupied).

Step 2: Create the Seat View

We need a visual representation of our seat:

struct SeatView: View {
    var seat: Seat

    var body: some View {
        Text(seat.id.letter)
            .frame(width: 40, height: 40)
            .background(seat.state == .empty ? Color.green : Color.red)
            .cornerRadius(8)
            .overlay(
                RoundedRectangle(cornerRadius: 8)
                    .stroke(Color.black, lineWidth: 2)
            )
    }
}

The SeatView displays the seat letter and changes its background based on its state.

Step 3: Build the Seat Map

Our goal is a grid layout with 2 seats, an aisle with a row number, 3 seats, another aisle, and then 2 more seats:

struct FirstClassView: View {

    @State var seats: [Seat] = (1..<25).map { row in
        ["A", "B", "C", "D", "E", "F", "G"].map { letter in
            Seat(id: SeatId(row: row, letter: letter), state: .empty)
        }
    }.flatMap { $0 }

    var columns: [GridItem] = [
        .init(.flexible()),  // A seat
        .init(.flexible()),  // B seat
        .init(.fixed(40)),   // Aisle with row number
        .init(.flexible()),  // C seat
        .init(.flexible()),  // D seat
        .init(.flexible()),  // E seat
        .init(.fixed(40)),   // Aisle with row number
        .init(.flexible()),  // F seat
        .init(.flexible())   // G seat
    ]

    var body: some View {
        ScrollView([.vertical, .horizontal], showsIndicators: true) {
            LazyVGrid(columns: columns, spacing: 20) {
                ForEach(seats) { seat in
                    switch seat.id.letter {
                    case "A", "B", "C", "D", "E", "F", "G":
                        SeatView(seat: seat)
                            .onTapGesture {
                                toggleSeat(seat: seat)
                            }
                    default:
                        Spacer()
                    }

                    if seat.id.letter == "B" || seat.id.letter == "E" {
                        Text("\(seat.id.row)")
                            .font(.headline)
                            .frame(width: 40, height: 40)
                    }
                }
            }
            .padding()
        }
    }

    func toggleSeat(seat: Seat) {
        if let index = seats.firstIndex(of: seat) {
            seats[index].state = seats[index].state == .empty ? .occupied : .empty
        }
    }
}

With SwiftUI, building complex layouts becomes a breeze. Our seat map, with different configurations and aisles, is just a demonstration of how adaptable and flexible SwiftUI grids can be.

Remember, you can further customize the appearance, add more features like zooming, selecting multiple seats, or fetching seat availability from a server. The possibilities are limitless! Happy coding!

Read more
Stories
October 27, 2025
AWS Outage Reminds Us "Smart" Devices Are Only as Smart as Their Architecture
by
Ryan Ratner
When a 15-hour AWS outage turned $2,700 smart beds into saunas and left thousands of restaurants unable to process orders, it exposed the fatal flaw in how we're building edge applications—and why it's time to rethink everything
Product
October 24, 2025
Beyond GOTS: The Case for Commercial Edge Sync in Defense and Public Sector Operations
by
Mustafa Durrani
Leverage the scale, agility, and innovation velocity of the commercial market while maintaining the capability to integrate government-grade security requirements.