Categories
Swift SwiftUI

Opening hyperlinks in SwiftUI

Opening hyperlinks in UIKit with UILabel is unexpectedly complex, what about SwiftUI? In this post, we’ll dive into opening hyperlinks in SwiftUI.

If we just would like to show a hyperlink, then the best way is to the Link view. We can just feed it with a title and the destination URL. In addition, we can even apply a button style to it.

Link("Silky Brew", destination: AppConstants.URLs.silkyBrew)
  .buttonStyle(.borderedProminent)

By default, URLs are opened in the default web browser or if we are dealing with universal links, then in the appropriate app. If we have a desire to change how links are opened, we can apply a custom OpenURLAction. Here is an example how to open a URL in SFSafariViewController (SafariURL is just an Identifiable supported URL wrapper used for sheet’s binding and SafariView is SFSafariViewController wrapper with UIViewControllerRepresentable).

Link("Signal Path", destination: AppConstants.URLs.signalPath)
  .environment(\.openURL, OpenURLAction(handler: { url in
    safariURL = SafariURL(url: url)
    return .handled
}))
  .sheet(item: $safariURL, content: { safariURL in
    SafariView(url: safariURL.url) 
  })

Often we are dealing with a case where we have text which contains some links as well. In comparison to UIKit, it is way more simple. We can just use the Markdown syntax to define the link and that is all to it.

Text("Hello, world! Here is my [blog](https://augmentedcode.io/blog)")

If we would like to use a custom URL handler, then we can override the default handler through the openURL environment value. Can be handy to just have keys for URL in text and substituting these with actual URLs when handling the tap.

Text("Here are some apps: [Silky Brew](silky), [Signal Path](signal), and [Drifty Asteroid](drifty)")
                .environment(\.openURL, OpenURLAction(handler: { url in
                    switch url.absoluteString {
                    case "drifty": .systemAction(AppConstants.URLs.driftyAsteroid)
                    case "signal": .systemAction(AppConstants.URLs.signalPath)
                    case "silky": .systemAction(AppConstants.URLs.silkyBrew)
                    default: .systemAction
                    }
                }))

When talking about the OpenURLAction in greater detail, then the different return values are:

  • handled – handler took care of opening the URL (e.g. opening the URL in SFSafariViewController)
  • discarded – handler ignored the handling
  • systemAction – system handler opens the URL
  • systemAction(_:) – use a different URL (e.g. adding query parameters)

If this was helpful, please let me know on Mastodon@toomasvahter or Twitter @toomasvahter. Feel free to subscribe to RSS feed. Thank you for reading.