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

# SwiftUI - Custom vector icons

Your browser doesn't support HTML5 video. Open [link to the video](https://static-assets.mapbox.com/maps/ios/documentation/CustomVectorIcons.mp4).

This example demonstrates how to dynamically colorize vector icons at runtime using the **Mapbox Maps SDK for iOS** in a SwiftUI environment. The `CustomVectorIconsExample` struct creates a [`Map`](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxmaps/map/) with a custom Mapbox Studio style that includes a parameterized SVG flag icon, then places three instances of that icon at specific coordinates with distinct colors.

Icon colorization is achieved using the [`image` expression](https://docs.mapbox.com/style-spec/reference/expressions/#types-image) on a [`SymbolLayer`](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxmaps/symbollayer/), passing a `params` dictionary that maps the icon's `flag_color` parameter to the `flagColor` property on each [`GeoJSONSource`](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxmaps/geojsonsource/) feature. A [`case` expression](https://docs.mapbox.com/style-spec/reference/expressions/#case) on [`iconSize`](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxmaps/symbollayer/iconsize/) toggles the tapped icon between 1× and 2× scale. Tap interactions are handled using [`TapInteraction`](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxmaps/tapinteraction/) scoped to the symbol layer.

> **Note: iOS Examples App Available**
> 
> This example code is part of the **Maps SDK for iOS Examples App**, a working iOS project [available on Github](https://github.com/mapbox/mapbox-maps-ios/tree/11.29.0/Sources/Examples). iOS developers are encouraged to run the examples app locally to interact with this example in an emulator and explore other features of the Maps SDK.
> 
> See our [Run the Maps SDK for iOS Examples App](https://docs.mapbox.com/help/tutorials/maps-sdk-ios-examples-app/) tutorial for step-by-step instructions.

**Swift**

Title: `CustomVectorIconsExample.swift`

[View on GitHub](https://github.com/mapbox/mapbox-maps-ios/blob/main/Sources/Examples/SwiftUI%20Examples/CustomVectorIconsExample.swift)

```swift
import SwiftUI
import MapboxMaps

/// Example demonstrating custom vector icons with dynamic styling and interaction.
/// This example shows how to:
/// - Dynamically colorize vector icons based on feature properties using the image expression
/// - Interactively change icon size by tapping on icons
///
/// Vector icons are parameterized SVG images that can be styled at runtime. In this example,
/// three flag icons are colored red, yellow, and purple using the 'flagColor' property.
/// Tap any flag to toggle its size between 1x and 2x.
///
/// For this example to work, the SVGs must live inside the map style. The SVG file was uploaded
/// to Mapbox Studio with the name `flag`, making it available for customization at runtime.
/// You can add vector icons to your own style in Mapbox Studio.
struct CustomVectorIconsExample: View {
    @State private var selectedFlagId: String?

    var body: some View {
        Map(initialViewport: .camera(center: CLLocationCoordinate2D(latitude: 60.185755, longitude: 24.6881), zoom: 16)) {
            // Create GeoJSON source with three flag locations
            GeoJSONSource(id: "points")
                .data(.featureCollection(flagFeatures))

            // Create symbol layer with parameterized icon
            SymbolLayer(id: "points", source: "points")
                .iconImage(
                    Exp(.image) {
                        "flag"
                        ["params": ["flag_color": Exp(.get) { "flagColor" }]]
                    }
                )
                .iconSize(
                    Exp(.switchCase) {
                        Exp(.eq) {
                            Exp(.get) { "id" }
                            selectedFlagId ?? ""
                        }
                        2.0
                        1.0
                    }
                )
                .iconAllowOverlap(true)

            // Add tap interaction for the symbol layer
            TapInteraction(.layer("points")) { feature, _ in
                if let id = feature.properties["id"]??.rawValue as? String {
                    selectedFlagId = (selectedFlagId == id) ? nil : id
                }
                return true
            }
        }
        .mapStyle(MapStyle(uri: StyleURI(rawValue: "mapbox://styles/mapbox-map-design/cm4r19bcm00ao01qvhp3jc2gi")!))
        .ignoresSafeArea()
    }

    /// GeoJSON features with flag locations and colors
    private var flagFeatures: FeatureCollection {
        FeatureCollection(features: [
            createFlagFeature(
                id: "flag-red",
                longitude: 24.68727,
                latitude: 60.185755,
                color: "red"
            ),
            createFlagFeature(
                id: "flag-yellow",
                longitude: 24.68827,
                latitude: 60.186255,
                color: "yellow"
            ),
            createFlagFeature(
                id: "flag-purple",
                longitude: 24.68927,
                latitude: 60.186055,
                color: "#800080"
            )
        ])
    }

    /// Creates a feature with a flag at the specified location and color
    private func createFlagFeature(id: String, longitude: Double, latitude: Double, color: String) -> Feature {
        var feature = Feature(geometry: .point(Point(CLLocationCoordinate2D(latitude: latitude, longitude: longitude))))
        feature.properties = [
            "id": .string(id),
            "flagColor": .string(color)
        ]
        return feature
    }
}
```