> For the complete documentation index, see [llms.txt](https://docs.mapbox.com/help/ja/llms.txt)

# Add Interactions to your Map on iOS

This tutorial teaches you how to add interactions to your map using the **Mapbox Maps SDK for iOS** with the [Interactions API](https://docs.mapbox.com/ios/maps/guides/user-interaction/Interactions/) when using the [Mapbox Standard](https://docs.mapbox.com/map-styles/standard/) style. You will learn to import styles, access [featuresets](https://docs.mapbox.com/style-spec/reference/featuresets/) in those fragments, and add interactions to your map.

Your browser doesn't support HTML5 video. Open [link to the video](https://docs.mapbox.com/help/ja/help/ja/assets/medias/tutorials--ios-interactions-complete-1e7c7f3811f9af5dc9b780c7fe4cff81.mp4).

## Prerequisites

Before you begin, you will need:

-   A **Mapbox account**: [Sign up](https://account.mapbox.com/auth/signup/) for free or [log in](https://console.mapbox.com/) if you already have an account.
-   **A project with the Maps SDK installed**: Follow the [Getting Started with the Maps SDK for iOS](https://docs.mapbox.com/ios/maps/guides/install/) guide.
-   **Xcode**: Version 16.2 or later
-   **Familiarity with iOS development**: Beginner experience with Swift and iOS Development..

This tutorial assumes you have a basic understanding of Swift and iOS development and requires you to have setup the **Mapbox Maps SDK for iOS** in a SwiftUI project as covered in our [Getting Started with Mapbox on iOS](https://docs.mapbox.com/ios/maps/guides/install/) guide. That guide walks you through adding the **Mapbox Maps SDK for iOS** dependency (version 11.13.0 or later) and adding your public access token to your project's `Info.plist` file as seen below.

![Screenshot of the Info.plist file with the MBXAccessToken key highlighted.](https://docs.mapbox.com/help/ja/assets/ideal-img/tutorials--ios-mbxaccesstoken.6cfa0af.480.png)

The Getting Started guide should leave you with a new SwiftUI project open in Xcode with a globe displayed.

![Screenshot of an iOS app showing a globe.](https://docs.mapbox.com/help/ja/assets/ideal-img/tutorials--ios-interactions-1.6eb9a5b.480.png)

## Add Interactions to your Map with the Standard Style

The [Mapbox Standard Style](https://docs.mapbox.com/map-styles/standard/guides/) is a good starting point for adding interactions to your map. When creating a new project, the Mapbox Standard Style is the default style. It has predefined [configuration options](https://docs.mapbox.com/map-styles/standard/guides/#configuration/) that allow you to set lighting conditions, label visibility, and other map features. Also, the Standard Style defines several [Featuresets](https://docs.mapbox.com/map-styles/standard/guides/#interactions-with-featuresets)—Standard Buildings, Standard Place Labels, and Standard POIs—that you can use to add interactions to your map.

To start, set the Map's camera to New York City and change the `lightPreset` configuration option for standard to `dawn`. Replace the body of the `ContentView` struct in your `ContentView.swift` file with the following code:

Your `ContentView.swift` file should look like this:

```swift
import SwiftUI
import MapboxMaps

struct ContentView: View {
    var body: some View {
        Map(initialViewport: .camera(center: .init(latitude: 40.72, longitude: -73.99), zoom: 11, pitch: 45)) {

        }
        .mapStyle(.standard(
            lightPreset: .dawn
        ))
        .ignoresSafeArea()
    }
}

#Preview {
    ContentView()
}
```

Now, you can add your first interaction. Start by adding a [`TapInteraction`](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxmaps/tapinteraction/) targeting the [`standardPlaceLabels`](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxmaps/featuresetdescriptor/standardplacelabels/) featureset. When a user taps on a place label, we will change the color of the label to red. To do this, first add a `TapInteraction` to the `Map`:

```swift
import SwiftUI
import MapboxMaps

struct ContentView: View {
    @State var selectedPlaces = [StandardPlaceLabelsFeature]()

    var body: some View {
        Map(initialViewport: .camera(center: .init(latitude: 40.72, longitude: -73.99), zoom: 11, pitch: 45)) {
            TapInteraction(.standardPlaceLabels) { placeLabel, context in
                print(placeLabel.name)
                print(context.coordinate)
                return true // This stops the tap event from propagating to the map
            }
        }
        .mapStyle(.standard(
            lightPreset: .dawn
        ))
        .ignoresSafeArea()
    }
}

#Preview {
    ContentView()
}
```

The `TapInteraction` takes two parameters: the featureset to target and a closure that is called when a user interacts with a map feature in that featureset. In this case, we are targeting the `standardPlaceLabels` featureset, which contains place labels such as the names of countries, cities, and neighborhoods. When a user taps on a place label, the provided closure will be called. When writing your closure you can access properties of the specific tapped feature (`placeLabel`) and the interaction context (`context`). For example, the above code will print the name of the place label and the coordinate of the tap to the console.

These properties are available in the closure because we are targeting the `.standardPlaceLabels` featureset meaning the `placeLabel` object has a type of [`standardPlaceLabelsFeature`](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxmaps/standardplacelabelsfeature/). This `placeLabel` object will contain information about the place label, such as its name, properties, and geometry. The `context` is of type [`InteractionContext`](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxmaps/interactioncontext/) and contains information about the interaction itself, such as the coordinate of the tap in latitude and longitude and the screen coordinate of the tap in pixels.

> **Note: Standard Style Featuresets**
> 
> Each featureset in the Mapbox Standard Style is typed, meaning that you can access the properties of features in that featureset directly. This allows you to work with the features in a type-safe way, making it easier to work with the data and reducing the risk of runtime errors.

Now, change that code so when place labels are selected their color changes to red. First, create a new `@State` variable to hold the selected place labels. This will keep track of which place labels have been selected and update the map as needed. Name this variable `selectedPlaces` and add it to the `ContentView` struct:

```swift
import SwiftUI
import MapboxMaps

struct ContentView: View {
    @State var selectedPlaces = [StandardPlaceLabelsFeature]()

    var body: some View {
        Map(initialViewport: .camera(center: .init(latitude: 40.72, longitude: -73.99), zoom: 11, pitch: 45)) {
            TapInteraction(.standardPlaceLabels) { placeLabel, context in
                print(placeLabel.name)
                print(context.coordinate)
                return true // This stops the tap event from propagating to the map
            }
        }
        .mapStyle(.standard(
            lightPreset: .dawn
        ))
        .ignoresSafeArea()
    }
}

#Preview {
    ContentView()
}
```

Each typed [`FeaturesetFeature`](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxmaps/featuresetfeature/) has a `State` object that contains properties that you can set to change the appearance of the feature. For `standardPlaceLabelsFeature`, you can set the [feature state](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxmaps/standardplacelabelsfeature/) for `hide`, `select`, and `highlight`. You can learn about these properties in the `standardPlaceLabelsFeature` [documentation](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxmaps/standardplacelabelsfeature/state-swift.struct/).

Update the `TapInteraction` closure to append the selected place label to the `selectedPlaces` array. Then, use `ForEvery` to loop through the `selectedPlaces` array to change the [`FeatureState`](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxmaps/featurestate/) of the `select` property to true for each selected place label. The default color for selected place labels is red.

```swift
import SwiftUI
import MapboxMaps

struct ContentView: View {
    @State var selectedPlaces = [StandardPlaceLabelsFeature]()

    var body: some View {
        Map(initialViewport: .camera(center: .init(latitude: 40.72, longitude: -73.99), zoom: 11, pitch: 45)) {
            TapInteraction(.standardPlaceLabels) { placeLabel, _ in
                selectedPlaces.append(placeLabel)
                return true
            }

            ForEvery(selectedPlaces, id: \.id) { placeLabel in
                FeatureState(placeLabel, .init(select: true))
            }

            LongPressInteraction { _ in
                selectedPlaces.removeAll()
                return true
            }
        }
        .mapStyle(.standard(
            lightPreset: .dawn
        ))
        .ignoresSafeArea()
    }
}

#Preview {
    ContentView()
}
```

Next, add an additional [`LongPressInteraction`](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxmaps/longpressinteraction/), targeting the map itself. The `LongPressInteraction` takes a closure that is called when the interaction occurs. In this case, it will remove all elements from the `selectedPlaces` array, which will remove the red coloring of the selected place labels.

```swift
import SwiftUI
import MapboxMaps

struct ContentView: View {
    @State var selectedPlaces = [StandardPlaceLabelsFeature]()

    var body: some View {
        Map(initialViewport: .camera(center: .init(latitude: 40.72, longitude: -73.99), zoom: 11, pitch: 45)) {
            TapInteraction(.standardPlaceLabels) { placeLabel, _ in
                selectedPlaces.append(placeLabel)
                return true
            }

            ForEvery(selectedPlaces, id: \.id) { placeLabel in
                FeatureState(placeLabel, .init(select: true))
            }

            LongPressInteraction { _ in
                selectedPlaces.removeAll()
                return true
            }
        }
        .mapStyle(.standard(
            lightPreset: .dawn
        ))
        .ignoresSafeArea()
    }
}

#Preview {
    ContentView()
}
```

![Screenshot of an iOS app showing a map of New York City with several selected red place labels.](https://docs.mapbox.com/help/ja/assets/ideal-img/tutorials--ios-interactions-2.8fcd4d6.480.png)

## Import another style to your map

When working with the Mapbox Standard Style you can [import additional styles](https://docs.mapbox.com/map-styles/standard/guides/#style-imports/) to your map. This allows you to add specific data and featuresets to your map. For this tutorial, you will need to download the `new-york-hotels` style, which contains a featureset of hotels data and add it to your Xcode project. To add the file to your project, select File > Add Files to "YourProjectName"... and select the JSON file. Make sure the Action is "Copy files to destination" and you select the correct target.

[Download JSON](https://docs.mapbox.com/help/ja/help/ja/data/new-york-hotels.json)

### Import the New York Hotels Style

To import the `new-york-hotels` style, add the following code to your `ContentView.swift` file outside of the `ContentView` at the bottom of the file:

```swift
import SwiftUI
import MapboxMaps

struct ContentView: View {
    @State var selectedPlaces = [StandardPlaceLabelsFeature]()

    var body: some View {
        Map(initialViewport: .camera(center: .init(latitude: 40.72, longitude: -73.99), zoom: 11, pitch: 45)) {
            StyleImport(id: "new-york-hotels", uri: StyleURI(url: styleURL)!)

            TapInteraction(.standardPlaceLabels) { placeLabel, _ in
                selectedPlaces.append(placeLabel)
                return true
            }

            ForEvery(selectedPlaces, id: \.id) { placeLabel in
                FeatureState(placeLabel, .init(select: true))
            }

            LongPressInteraction { _ in
                selectedPlaces.removeAll()
                return true
            }
        }
        .mapStyle(.standard(
            lightPreset: .dawn
        ))
        .ignoresSafeArea()
    }
}

private let styleURL = Bundle.main.url(forResource: "new-york-hotels", withExtension: "json")!

#Preview {
    ContentView()
}
```

Then, in your `Map` body, add the following code to import the style:

```swift
import SwiftUI
import MapboxMaps

struct ContentView: View {
    @State var selectedPlaces = [StandardPlaceLabelsFeature]()

    var body: some View {
        Map(initialViewport: .camera(center: .init(latitude: 40.72, longitude: -73.99), zoom: 11, pitch: 45)) {
            StyleImport(id: "new-york-hotels", uri: StyleURI(url: styleURL)!)

            TapInteraction(.standardPlaceLabels) { placeLabel, _ in
                selectedPlaces.append(placeLabel)
                return true
            }

            ForEvery(selectedPlaces, id: \.id) { placeLabel in
                FeatureState(placeLabel, .init(select: true))
            }

            LongPressInteraction { _ in
                selectedPlaces.removeAll()
                return true
            }
        }
        .mapStyle(.standard(
            lightPreset: .dawn
        ))
        .ignoresSafeArea()
    }
}

private let styleURL = Bundle.main.url(forResource: "new-york-hotels", withExtension: "json")!

#Preview {
    ContentView()
}
```

If you rebuild your app, you should see the new style imported into your map. It will show subway lines, small circles representing real estate listings, and several pop-ups with price information about the listings.

![Screenshot of an iOS app showing a map of New York City with hotel listings.](https://docs.mapbox.com/help/ja/assets/ideal-img/tutorials--ios-interactions-3.62dd32b.480.png)

## Add a TapInteraction to the Hotel Listings

Next, let's add a `TapInteraction` to the real estate listings. The `new-york-hotels` style contains a featureset called `hotels-price`. This featureset exposes the price of hotels in New York City. To add a `TapInteraction` to the `hotels-price` featureset, add the following code to your `ContentView`:

```swift
import SwiftUI
import MapboxMaps

struct ContentView: View {
    @State var selectedPlaces = [StandardPlaceLabelsFeature]()
    @State private var selectedPriceLabel: FeaturesetFeature?

    var body: some View {
        Map(initialViewport: .camera(center: .init(latitude: 40.72, longitude: -73.99), zoom: 11, pitch: 45)) {
            StyleImport(id: "new-york-hotels", uri: StyleURI(url: styleURL)!)

            TapInteraction(.standardPlaceLabels) { placeLabel, _ in
                selectedPlaces.append(placeLabel)
                return true
            }

            ForEvery(selectedPlaces, id: \.id) { placeLabel in
                FeatureState(placeLabel, .init(select: true))
            }

            LongPressInteraction { _ in
                selectedPlaces.removeAll()
                return true
            }

            TapInteraction(.featureset("hotels-price", importId: "new-york-hotels")) { priceLabel, _ in
                /// Select a price label when it's clicked
                selectedPriceLabel = priceLabel
                return true
            }

            if let selectedPriceLabel, let coordinate = selectedPriceLabel.geometry.point?.coordinates {
                /// When there's a selected price label, we use it to set a feature state.
                /// The `hidden` state is implemented in `new-york-hotels.json` and hides label and icon.
                FeatureState(selectedPriceLabel, ["hidden": true])

                /// Instead of label we show a callout annotation with animation.
                MapViewAnnotation(coordinate: coordinate) {
                    HotelCallout(feature: selectedPriceLabel)
                    /// The `id` makes the view to be re-created for each unique feature
                    /// so appearing animation plays each time.
                        .id(selectedPriceLabel.id)
                }
                .variableAnchors([.init(anchor: .bottom)])
            }
        }
        .mapStyle(.standard(
            lightPreset: .dawn
        ))
        .ignoresSafeArea()
    }
}

private struct HotelCallout: View {
    var feature: FeaturesetFeature

    @State private var scale: CGFloat = 0.1

    var body: some View {
        VStack(alignment: .center, spacing: 2) {
            Text(feature.properties["name"]??.string ?? "—")
                .font(.headline)
                .foregroundColor(.black)
            Text(feature.properties["price"]??.number.map { "$ \(Int($0))" } ?? "—")
                .font(.subheadline)
                .foregroundColor(.green)
                .fontWeight(.bold)
        }
        .padding(6)
        .background(Color.white.opacity(0.9))
        .cornerRadius(8)
        .scaleEffect(scale, anchor: .bottom)
        .onAppear {
            withAnimation(Animation.interpolatingSpring(stiffness: 200, damping: 16)) {
                scale = 1.0
            }
        }
    }
}

private let styleURL = Bundle.main.url(forResource: "new-york-hotels", withExtension: "json")!

#Preview {
    ContentView()
}
```

Then add the following code to your `Map` body, which will add a `TapInteraction` to the `hotels-price` featureset. The `selectedPriceLabel` variable will hold the selected price label, which we will use to add a `MapViewAnnotation` to the selected price label.

```swift
import SwiftUI
import MapboxMaps

struct ContentView: View {
    @State var selectedPlaces = [StandardPlaceLabelsFeature]()
    @State private var selectedPriceLabel: FeaturesetFeature?

    var body: some View {
        Map(initialViewport: .camera(center: .init(latitude: 40.72, longitude: -73.99), zoom: 11, pitch: 45)) {
            StyleImport(id: "new-york-hotels", uri: StyleURI(url: styleURL)!)

            TapInteraction(.standardPlaceLabels) { placeLabel, _ in
                selectedPlaces.append(placeLabel)
                return true
            }

            ForEvery(selectedPlaces, id: \.id) { placeLabel in
                FeatureState(placeLabel, .init(select: true))
            }

            LongPressInteraction { _ in
                selectedPlaces.removeAll()
                return true
            }

            TapInteraction(.featureset("hotels-price", importId: "new-york-hotels")) { priceLabel, _ in
                /// Select a price label when it's clicked
                selectedPriceLabel = priceLabel
                return true
            }

            if let selectedPriceLabel, let coordinate = selectedPriceLabel.geometry.point?.coordinates {
                /// When there's a selected price label, we use it to set a feature state.
                /// The `hidden` state is implemented in `new-york-hotels.json` and hides label and icon.
                FeatureState(selectedPriceLabel, ["hidden": true])

                /// Instead of label we show a callout annotation with animation.
                MapViewAnnotation(coordinate: coordinate) {
                    HotelCallout(feature: selectedPriceLabel)
                    /// The `id` makes the view to be re-created for each unique feature
                    /// so appearing animation plays each time.
                        .id(selectedPriceLabel.id)
                }
                .variableAnchors([.init(anchor: .bottom)])
            }
        }
        .mapStyle(.standard(
            lightPreset: .dawn
        ))
        .ignoresSafeArea()
    }
}

private struct HotelCallout: View {
    var feature: FeaturesetFeature

    @State private var scale: CGFloat = 0.1

    var body: some View {
        VStack(alignment: .center, spacing: 2) {
            Text(feature.properties["name"]??.string ?? "—")
                .font(.headline)
                .foregroundColor(.black)
            Text(feature.properties["price"]??.number.map { "$ \(Int($0))" } ?? "—")
                .font(.subheadline)
                .foregroundColor(.green)
                .fontWeight(.bold)
        }
        .padding(6)
        .background(Color.white.opacity(0.9))
        .cornerRadius(8)
        .scaleEffect(scale, anchor: .bottom)
        .onAppear {
            withAnimation(Animation.interpolatingSpring(stiffness: 200, damping: 16)) {
                scale = 1.0
            }
        }
    }
}

private let styleURL = Bundle.main.url(forResource: "new-york-hotels", withExtension: "json")!

#Preview {
    ContentView()
}
```

Next, add code so that when a price label is selected it will replace the basic price label with a custom `HotelCallout` View. This view will display the name and price of the hotel listing. To do this, create a new `HotelCallout` struct that conforms to the `View` protocol. This struct will take a `FeaturesetFeature` as a parameter and display the name and price of the hotel listing. Add the following code to your `ContentView.swift` file outside of the `ContentView` struct:

```swift
import SwiftUI
import MapboxMaps

struct ContentView: View {
    @State var selectedPlaces = [StandardPlaceLabelsFeature]()
    @State private var selectedPriceLabel: FeaturesetFeature?

    var body: some View {
        Map(initialViewport: .camera(center: .init(latitude: 40.72, longitude: -73.99), zoom: 11, pitch: 45)) {
            StyleImport(id: "new-york-hotels", uri: StyleURI(url: styleURL)!)

            TapInteraction(.standardPlaceLabels) { placeLabel, _ in
                selectedPlaces.append(placeLabel)
                return true
            }

            ForEvery(selectedPlaces, id: \.id) { placeLabel in
                FeatureState(placeLabel, .init(select: true))
            }

            LongPressInteraction { _ in
                selectedPlaces.removeAll()
                return true
            }

            TapInteraction(.featureset("hotels-price", importId: "new-york-hotels")) { priceLabel, _ in
                /// Select a price label when it's clicked
                selectedPriceLabel = priceLabel
                return true
            }

            if let selectedPriceLabel, let coordinate = selectedPriceLabel.geometry.point?.coordinates {
                /// When there's a selected price label, we use it to set a feature state.
                /// The `hidden` state is implemented in `new-york-hotels.json` and hides label and icon.
                FeatureState(selectedPriceLabel, ["hidden": true])

                /// Instead of label we show a callout annotation with animation.
                MapViewAnnotation(coordinate: coordinate) {
                    HotelCallout(feature: selectedPriceLabel)
                    /// The `id` makes the view to be re-created for each unique feature
                    /// so appearing animation plays each time.
                        .id(selectedPriceLabel.id)
                }
                .variableAnchors([.init(anchor: .bottom)])
            }
        }
        .mapStyle(.standard(
            lightPreset: .dawn
        ))
        .ignoresSafeArea()
    }
}

private struct HotelCallout: View {
    var feature: FeaturesetFeature

    @State private var scale: CGFloat = 0.1

    var body: some View {
        VStack(alignment: .center, spacing: 2) {
            Text(feature.properties["name"]??.string ?? "—")
                .font(.headline)
                .foregroundColor(.black)
            Text(feature.properties["price"]??.number.map { "$ \(Int($0))" } ?? "—")
                .font(.subheadline)
                .foregroundColor(.green)
                .fontWeight(.bold)
        }
        .padding(6)
        .background(Color.white.opacity(0.9))
        .cornerRadius(8)
        .scaleEffect(scale, anchor: .bottom)
        .onAppear {
            withAnimation(Animation.interpolatingSpring(stiffness: 200, damping: 16)) {
                scale = 1.0
            }
        }
    }
}

private let styleURL = Bundle.main.url(forResource: "new-york-hotels", withExtension: "json")!

#Preview {
    ContentView()
}
```

Now, add the following code to your `Map` body, which will create a `MapViewAnnotation` for the selected price label feature using the `HotelCallout` View. The `coordinate` of the selected price label will set the position of the annotation. The `id` of the annotation will be the `id` of the selected price label feature, which allows the annotation to be re-created for each unique feature. This will cause the appearing animation to play each time a new price label is selected. Finally, we set the `hidden` state of the selected price label to true, which will hide the original price label.

```swift
import SwiftUI
import MapboxMaps

struct ContentView: View {
    @State var selectedPlaces = [StandardPlaceLabelsFeature]()
    @State private var selectedPriceLabel: FeaturesetFeature?

    var body: some View {
        Map(initialViewport: .camera(center: .init(latitude: 40.72, longitude: -73.99), zoom: 11, pitch: 45)) {
            StyleImport(id: "new-york-hotels", uri: StyleURI(url: styleURL)!)

            TapInteraction(.standardPlaceLabels) { placeLabel, _ in
                selectedPlaces.append(placeLabel)
                return true
            }

            ForEvery(selectedPlaces, id: \.id) { placeLabel in
                FeatureState(placeLabel, .init(select: true))
            }

            LongPressInteraction { _ in
                selectedPlaces.removeAll()
                return true
            }

            TapInteraction(.featureset("hotels-price", importId: "new-york-hotels")) { priceLabel, _ in
                /// Select a price label when it's clicked
                selectedPriceLabel = priceLabel
                return true
            }

            if let selectedPriceLabel, let coordinate = selectedPriceLabel.geometry.point?.coordinates {
                /// When there's a selected price label, we use it to set a feature state.
                /// The `hidden` state is implemented in `new-york-hotels.json` and hides label and icon.
                FeatureState(selectedPriceLabel, ["hidden": true])

                /// Instead of label we show a callout annotation with animation.
                MapViewAnnotation(coordinate: coordinate) {
                    HotelCallout(feature: selectedPriceLabel)
                    /// The `id` makes the view to be re-created for each unique feature
                    /// so appearing animation plays each time.
                        .id(selectedPriceLabel.id)
                }
                .variableAnchors([.init(anchor: .bottom)])
            }
        }
        .mapStyle(.standard(
            lightPreset: .dawn
        ))
        .ignoresSafeArea()
    }
}

private struct HotelCallout: View {
    var feature: FeaturesetFeature

    @State private var scale: CGFloat = 0.1

    var body: some View {
        VStack(alignment: .center, spacing: 2) {
            Text(feature.properties["name"]??.string ?? "—")
                .font(.headline)
                .foregroundColor(.black)
            Text(feature.properties["price"]??.number.map { "$ \(Int($0))" } ?? "—")
                .font(.subheadline)
                .foregroundColor(.green)
                .fontWeight(.bold)
        }
        .padding(6)
        .background(Color.white.opacity(0.9))
        .cornerRadius(8)
        .scaleEffect(scale, anchor: .bottom)
        .onAppear {
            withAnimation(Animation.interpolatingSpring(stiffness: 200, damping: 16)) {
                scale = 1.0
            }
        }
    }
}

private let styleURL = Bundle.main.url(forResource: "new-york-hotels", withExtension: "json")!

#Preview {
    ContentView()
}
```

![Screenshot of an iOS app showing a map of New York City with a price listing popup.](https://docs.mapbox.com/help/ja/assets/ideal-img/tutorials--ios-interactions-4.19f027c.480.png)

## Complete the App

Your app should now be complete! You can select place labels to change their color to red, and you can select hotel listings to show a custom callout with the price of the listing. You can also long press on the map to remove the selected place labels.

Your browser doesn't support HTML5 video. Open [link to the video](https://docs.mapbox.com/help/ja/help/ja/assets/medias/tutorials--ios-interactions-complete-1e7c7f3811f9af5dc9b780c7fe4cff81.mp4).

Your full `ContentView.swift` file should look like this:

```swift
import SwiftUI
import MapboxMaps

struct ContentView: View {
    @State var selectedPlaces = [StandardPlaceLabelsFeature]()
    @State private var selectedPriceLabel: FeaturesetFeature?

    var body: some View {
        Map(initialViewport: .camera(center: .init(latitude: 40.72, longitude: -73.99), zoom: 11, pitch: 45)) {
            StyleImport(id: "new-york-hotels", uri: StyleURI(url: styleURL)!)

            TapInteraction(.standardPlaceLabels) { placeLabel, _ in
                selectedPlaces.append(placeLabel)
                return true
            }

            ForEvery(selectedPlaces, id: \.id) { placeLabel in
                FeatureState(placeLabel, .init(select: true))
            }

            LongPressInteraction { _ in
                selectedPlaces.removeAll()
                return true
            }

            TapInteraction(.featureset("hotels-price", importId: "new-york-hotels")) { priceLabel, _ in
                /// Select a price label when it's clicked
                selectedPriceLabel = priceLabel
                return true
            }

            if let selectedPriceLabel, let coordinate = selectedPriceLabel.geometry.point?.coordinates {
                /// When there's a selected price label, we use it to set a feature state.
                /// The `hidden` state is implemented in `new-york-hotels.json` and hides label and icon.
                FeatureState(selectedPriceLabel, ["hidden": true])

                /// Instead of label we show a callout annotation with animation.
                MapViewAnnotation(coordinate: coordinate) {
                    HotelCallout(feature: selectedPriceLabel)
                    /// The `id` makes the view to be re-created for each unique feature
                    /// so appearing animation plays each time.
                        .id(selectedPriceLabel.id)
                }
                .variableAnchors([.init(anchor: .bottom)])
            }
        }
        .mapStyle(.standard(
            lightPreset: .dawn
        ))
        .ignoresSafeArea()
    }
}

private struct HotelCallout: View {
    var feature: FeaturesetFeature

    @State private var scale: CGFloat = 0.1

    var body: some View {
        VStack(alignment: .center, spacing: 2) {
            Text(feature.properties["name"]??.string ?? "—")
                .font(.headline)
                .foregroundColor(.black)
            Text(feature.properties["price"]??.number.map { "$ \(Int($0))" } ?? "—")
                .font(.subheadline)
                .foregroundColor(.green)
                .fontWeight(.bold)
        }
        .padding(6)
        .background(Color.white.opacity(0.9))
        .cornerRadius(8)
        .scaleEffect(scale, anchor: .bottom)
        .onAppear {
            withAnimation(Animation.interpolatingSpring(stiffness: 200, damping: 16)) {
                scale = 1.0
            }
        }
    }
}

private let styleURL = Bundle.main.url(forResource: "new-york-hotels", withExtension: "json")!

#Preview {
    ContentView()
}
```

## Next steps

Congratulations! You have successfully added interactions to your map using the **Mapbox Maps SDK for iOS**. You can now add custom styles and interactions to your map, allowing you to create a more engaging user experience.

### What we covered

-   Add a `TapInteraction` to the `standardPlaceLabels` featureset
-   Add a `LongPressInteraction` to remove selected place labels
-   Import a custom style to your map, and add a `TapInteraction` to the `hotels-price` featureset
-   Create a custom `MapViewAnnotation` to display the price of a hotel listing

### Learn more

If you'd like an additional challenge try implementing the following features:

-   Add an interaction to the subway lines to show the name of the subway line when tapped.
-   Adjust the styling of the `HotelCallout` view.
-   Instead of one selected price label, allow multiple price labels to be selected at once.

> **Related content (guide): [Learn about the Mapbox Standard Style](https://docs.mapbox.com/map-styles/standard/guides/)**
> 
> Learn more about the [Mapbox Standard Style](https://docs.mapbox.com/map-styles/standard/guides/) and how to use it in your iOS app.

> **Related content (guide): [Learn about the Interactions API](https://docs.mapbox.com/ios/maps/guides/user-interaction/Interactions/)**
> 
> Learn more about the [Interactions API](https://docs.mapbox.com/ios/maps/guides/user-interaction/Interactions/) and how to use it in your iOS app.

> **Related content (example): [Add interactions to predefined featuresets](https://docs.mapbox.com/ios/maps/examples/standard-style-interactions-ui-kit/)**
> 
> Learn how to add interactions to predefined featuresets using the Mapbox Maps SDK for iOS when using UI Kit.