You are currently viewing How to Define Custom URL Actions for SwiftUI Text Views

How to Define Custom URL Actions for SwiftUI Text Views

With the release of iOS 15, Apple has introduced native markdown support to the SwiftUI Text view. This feature allows developers to easily create strings with hyperlinks that can open websites, send emails, or make phone calls. While this feature may be sufficient in most cases, there are situations where developers might want more control over what happens when a link is tapped.

In this article, I will show you how to achieve greater control over link behavior in SwiftUI. Additionally, I will also share a few interesting use cases of custom URL action that you might find useful.

So, without further ado, let’s jump right in!


Using the `openURL` Environment View Modifier

With the release of iOS 15, Apple introduced the openURL environment view modifier, along with markdown support in the Text view. This modifier allows developers to define the action that will occur when a link is tapped. It can be easily used by appending it to a Text view, as shown in the sample code below:

Text("Find out more [here](https://www.apple.com)")
    .environment(\.openURL, OpenURLAction { url in
        
        // Do something here...
        
        return .systemAction
    })

It is important to note that at the end of the action handler, it is required to return the result of the action performed. This ensures that the system knows the final outcome of the custom action.

If you’re wondering about the available action results, here is a list of all the possibilities:

All available results of a custom open URL action in SwiftUI
Source: developer.apple.com

In the next section, we’ll take a look at some of the interesting use cases for this modifier.


Some Interesting Use Cases

Now that you understand how the openURL environment view modifier works, let’s take a look at a few of its interesting use cases.

Analytic Tracking

Let’s say we want to keep track of which URLs in a Text view users tap the most for analytical purposes, we can do it using the following approach:

Text("""
      Find out more:
        - [iPhone](https://www.apple.com/iphone/)
        - [iPad](https://www.apple.com/ipad/)
        - [Mac](https://www.apple.com/mac/)
""")
.environment(\.openURL, OpenURLAction { url in

    // Track url tapped
    Analytic.track(url)

    // Open the URL using default browser
    return .systemAction
})

After finishing tracking, it’s important not to modify the system’s default behavior. To achieve this, we can return .systemAction as the action result. This ensures that the system will proceed by opening the URL in the default browser.

Trigger Non-URL Related Actions

Besides normal URL interaction, we can also use the modifier to perform actions similar to a button. Please take a look at the following GIF:

Define custom URL action that is non-URL related
Changing color with links

Here’s how it’s done.

Text("Choose text color: [Red](FF0000), [Green](00FF00), [Blue](0000FF)")
    .environment(\.openURL, OpenURLAction { url in

        withAnimation {
            // Init color using hex
            // Refer: https://stackoverflow.com/a/56874327
            textColor = Color(hex: url.absoluteString)
        }

        return .handled
    })
    .foregroundColor(textColor)

As you can see, the markdown URL syntax is not limited to just URLs. We can essentially give it any string and pass it to the action handler. In this case, we are passing in the color hex code.

URL Modification

In cases where we need to modify the destination URL before opening it, the systemAction(_:) action result will come in handy. For instance, we can use it to append a UTM source to the destination URL.

Text("Find out more [here](https://www.apple.com)")
    .environment(\.openURL, OpenURLAction { url in

        // Create the URL with query items
        let queryItems = [URLQueryItem(name: "utm_source", value: "swiftsenpai")]
        let newURL = url.appending(queryItems: queryItems)

        // Open the URL with query items
        return .systemAction(newURL)
    })

Doing so will change the destination URL to:

https://www.apple.com/?utm_source=swiftsenpai

I hope you will find this article helpful. If you like this article, be sure to check out my other articles related to iOS development. You can also follow me on Twitter, and LinkedIn, and subscribe to my newsletter so that you won’t miss out on any of my upcoming articles.

Thanks for reading. 👨🏻‍💻


👋🏻 Hey!

While you’re still here, why not check out some of my favorite Mac tools on Setapp? They will definitely help improve your day-to-day productivity. Additionally, doing so will also help support my work.

  • Bartender: Superpower your menu bar and take full control over your menu bar items.
  • CleanShot X: The best screen capture app I’ve ever used.
  • PixelSnap: Measure on-screen elements with ease and precision.
  • iStat Menus: Track CPU, GPU, sensors, and more, all in one convenient tool.