What is the correct architecture for achieving a 2 column grid of cards that expand into a full screen view when tapped upon in SwiftUI?
21:27 16 May 2026

I am trying to make a notes view where the individual notes will be displayed in a scrollable grid of two columns. I want to make it so that if a note card is tapped upon, it opens the full note and takes over the entire screen. I can't just use withAnimation because that contains the card inside the LazyVGrid that I am using. I tried using matchedGeometry as follows but that brings in the expanded view from the top left instead of expanding the card.

struct CardView: View {
    
    let title: String
    
    let nameSpace: Namespace.ID
    
    var body: some View {
        VStack() {
            Text(title)
                .font(.headline)
                .foregroundStyle(.white)
        }
        .frame(width: 150, height: 200)
        .background(.blue)
        .matchedGeometryEffect(id: "card", in: nameSpace)
    }
}

struct ExpandedCardView: View {
    
    let title: String
    
    let nameSpace: Namespace.ID
    
    let screenWidth = UIScreen.main.bounds.width
    let screenHeight = UIScreen.main.bounds.height

    
    var body: some View {
        
        VStack {
            Text(title)
                .font(.title)
                .foregroundStyle(.white)
        }
        .frame(width: screenWidth, height: screenHeight)
        .background(.blue)
        .matchedGeometryEffect(id: "card", in: nameSpace)
    }
}

struct ParentView: View {
    
    @State private var cardExpanded: Bool = false
    @Namespace private var nameSpace
    
    var body: some View {
        
        ZStack {
            
            if (cardExpanded == false) {
                CardView(title: "This is a title", nameSpace: nameSpace)
                    .onTapGesture {
                        withAnimation {
                            cardExpanded.toggle()
                        }

                    }
            }
            else {
                ExpandedCardView(title: "This is a title", nameSpace: nameSpace)
                    .onTapGesture {
                        withAnimation {
                            cardExpanded.toggle()
                        }
                    }
                    .zIndex(1)
            }
        }
    }
}

I am not sure how to make this work. The look I am trying to achieve is similar to how tabs look in the Safari app on iOS. It is also similar to how the Files app works on iOS.

I really liked the animation I got by using withAnimation but because of the card not being able to escape the LazyVGrid, it didn't work as intended. The code using withAnimation is as follows:

struct CardView: View {
    @State var isExpanded: Bool = false
    let title: String
    
    let screenWidth = UIScreen.main.bounds.width
    let screenHeight = UIScreen.main.bounds.height
    
    var body: some View {
        VStack() {
            Text(title)
                .font(.headline)
                .scaleEffect(isExpanded ? 2 : 1)
                .foregroundColor(.white)
        }
        .frame(
            width: isExpanded ? screenWidth : 150,
            height: isExpanded ? screenHeight : 200
        )
        .background(Color.blue)
        .zIndex(isExpanded ? 1 : 0)
        .onTapGesture {
            withAnimation {
                isExpanded.toggle()
            }
        }
    }
}

struct ParentView: View {
    
    private let columns = [
        GridItem(.flexible(), spacing: 16),
        GridItem(.flexible(), spacing: 16)
    ]
    
    var body: some View {
        
        ZStack {
            
            ScrollView {
                
                LazyVGrid(columns: columns) {
                    
                    ForEach(0..<20) { _ in
                        CardView(title: "This is a title")
                    }
                    
                }
            }
            
        }
        
    }
}

I would appreciate if someone could help me understand what is correct architecture to achieive that look that I am trying to.

ios swift swiftui