'How to make hyperlinks in SwiftUI

In Swift, as shown here, you can use "NSMutableAttributedString" to embed links in text.

How can I achieve this with SwiftUI?

I implemented it as follows, but that does not look how I want it to. this.

import SwiftUI

struct ContentView: View {
    var body: some View {
        HStack {
            Text("By tapping Done, you agree to the ")
            Button(action: {}) {
                Text("privacy policy")
            }
            Text(" and ")
            Button(action: {}) {
                Text("terms of service")
            }
            Text(" .")
        }
    }
}


Solution 1:[1]

iOS 15+ (Swift 5.5 +)

SwiftUI has built-in support for rendering Markdown

To create a link, enclose the link text in brackets (e.g., [Duck Duck Go]) and then follow it immediately with the URL in parentheses (e.g., (https://duckduckgo.com)).

My favorite search engine is [Duck Duck Go](https://duckduckgo.com).

https://www.markdownguide.org/basic-syntax/#links

String variable

  1. Use init(_ value: String)

Creates a localized string key from the given string value.

let link = "[Duck Duck Go](https://duckduckgo.com)"
Text(.init(link))

Attributed text

  1. Use init(_ attributedContent: AttributedString)

Creates a text view that displays styled attributed content.

let markdownLink = try! AttributedString(markdown: "[Duck Duck Go](https://duckduckgo.com)")
Text(markdownLink)

Similar question: Making parts of text bold in SwiftUI


Use the Link View

A control for navigating to a URL.

https://developer.apple.com/documentation/swiftui/link

Link("Privacy Policy", destination: URL(string: "https://example.com")!)

Solution 2:[2]

Just as @mahan mention, this works perfectly for iOS 15.0 and above by using markdown language:

Text("[Privacy Policy](https://example.com)")

But if you're using a String variable, and put it into the Text it wouldn't work. Example:

let privacyPolicyText = "Read our [Privacy Policy](https://example.com) here."
Text(privacyPolicyText) // Will not work

Solution for using a String variable

The reason is that Text got multiple initiations. So how do we solve this? The easiest way is just to do:

let privacyPolicyText = "Read our [Privacy Policy](https://example.com) here."
Text(.init(privacyPolicyText))

Result: Read our Privacy Policy here.

Solution 3:[3]

it's very simple just use LocalizedStringKey for example:

let message = "Hello, www.google.com this is just testing for hyperlinks, check this out our website https://www.apple.in thank you."

Text(LocalizedStringKey(message))

Solution 4:[4]

It's always an option to wrap a UIKit view in UIViewRepresentable. Just have to go through the manual process of exposing each attribute you want to change.

struct AttributedText: UIViewRepresentable {
    var attributedText: NSAttributedString

    init(_ attributedText: NSAttributedString) {
        self.attributedText = attributedText
    }

    func makeUIView(context: Context) -> UITextView {
        return UITextView()
    }

    func updateUIView(_ label: UITextView, context: Context) {
        label.attributedText = attributedText
    }
}

//usage: AttributedText(NSAttributedString())

Solution 5:[5]

I know it's a bit late but I solved the same problem using HTML. First I created a small helper and link model.

struct HTMLStringView: UIViewRepresentable {
  let htmlContent: String

  func makeUIView(context: Context) -> WKWebView {
    return WKWebView()
  }

  func updateUIView(_ uiView: WKWebView, context: Context) {
    uiView.loadHTMLString(htmlContent, baseURL: nil)
  }
}

struct TextLink {
    let url: URL
    let title: String
}

Next I created function that changes String to HTML and replaces first occurrence of @link to my tappable link.

var content = "My string with @link."
var link = TextLink(url: URL(string: "https://www.facebook.com")!, title: "Facebook")
var body: some View {
    let bodySize = UIFont.preferredFont(forTextStyle: UIFont.TextStyle.body).pointSize
    var html = "<span style=\"font: -apple-system-body; font-size:calc(\(bodySize)px + 1.0vw)\">"

    if let linkRange = content.range(of: "@link") {
        let startText = content[content.startIndex ..< linkRange.lowerBound]
        let endText = content[linkRange.upperBound ..< content.endIndex]
        html += startText
        html += "<a href=\"\(link.url.absoluteString)\">\(link.title)</a>"
        html += endText
    } else {
        html += content
    }
    
    html += "</span>"
    
    return HTMLStringView(htmlContent: html)
}

Solution 6:[6]

I tried concatenated Texts with Link in between and these are the ways for iOS 15+ and below iOS 15.

    if #available(iOS 15, *) {
        
        Text("[Seperate Link 1 ](https://www.android.com/intl/en_in/)")
            .font(.caption)
            .foregroundColor(Color.green)
        // green color is not applied.

        Text("[Seperate Link 2 ](https://www.apple.com/in/)")
            .font(.caption)
            .accentColor(Color.green)
        // green is applied.
        
        Text("By authorizing you agree?our ")
            .font(.caption)
            .foregroundColor(Color.black)
        + Text("[Terms and Conditions](https://www.android.com/intl/en_in/)")
            .font(.caption)
            .foregroundColor(Color.green) // default blue is applied
        + Text(" and ")
            .font(.caption)
            .foregroundColor(Color.black)
        + Text("[Privacy Policy](https://www.apple.com/in/)")
            .font(.caption)
            .foregroundColor(Color.green) // default blue
        // cannot use accentColor(Color.green) here
    }
    else{
        // lower iOS versions.
        VStack{
            Text("By authorizing you agree our ")
                .font(.caption)
                .foregroundColor(Color.black)
            
            HStack(spacing: 4 ) {
                Text("Terms and Conditions")
                    .font(.caption)
                    .foregroundColor(Color.green)
                    .onTapGesture {
                        let url = URL.init(string: "https://www.android.com/intl/en_in/")
                        guard let termsAndConditionURL = url, UIApplication.shared.canOpenURL(termsAndConditionURL) else { return }
                        UIApplication.shared.open(termsAndConditionURL)
                    }
                Text("and")
                    .font(.caption)
                    .foregroundColor(Color.black)
                Text("Privacy Policy")
                    .font(.caption)
                    .foregroundColor(Color.green)
                    .onTapGesture {
                        let url = URL.init(string: "https://www.apple.com/in/")
                        guard let privacyPolicyURL = url, UIApplication.shared.canOpenURL(privacyPolicyURL) else { return }
                        UIApplication.shared.open(privacyPolicyURL)
                    }
            }
            
        }
        
    }

Solution 7:[7]

From the given documentation I got this = "You can update responsive options by breakpoints or by passing an object to Splide#options..." You can use Slide#options, if breakpoints not working.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3 MegaApp Studio
Solution 4 Joe
Solution 5 TheLegend27
Solution 6
Solution 7 Farrukh Ali