WKWebView
target="_blank"
iOS development
link handling
web view issues

Why is WKWebView not opening links with target_blank?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Links with target="_blank" work in Safari because the browser knows how to create another browsing context. WKWebView does not open a new tab or window automatically, so those links appear to do nothing unless your app handles the request.

WKWebView is a view embedded inside your app, not a full browser shell. When a page requests a new window through target="_blank" or window.open, WebKit asks the app whether it wants to create another web view.

If you do not implement the UI delegate path, there is nowhere for the new page to go.

In practice, the navigation action usually arrives with no target frame. That is the signal that the page is asking for a new browsing context instead of navigating inside the current one.

The Standard Fix

Set a WKUIDelegate and implement webView(_:createWebViewWith:for:windowFeatures:). If you do not want multiple web views, the simplest fix is to load the request in the existing WKWebView when the target frame is missing.

swift
1import UIKit
2import WebKit
3
4final class ViewController: UIViewController, WKUIDelegate {
5    private var webView: WKWebView!
6
7    override func viewDidLoad() {
8        super.viewDidLoad()
9
10        let config = WKWebViewConfiguration()
11        webView = WKWebView(frame: view.bounds, configuration: config)
12        webView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
13        webView.uiDelegate = self
14        view.addSubview(webView)
15
16        let html = """
17        <html>
18          <body>
19            <a href=\"https://example.com\" target=\"_blank\">Open link</a>
20          </body>
21        </html>
22        """
23        webView.loadHTMLString(html, baseURL: nil)
24    }
25
26    func webView(
27        _ webView: WKWebView,
28        createWebViewWith configuration: WKWebViewConfiguration,
29        for navigationAction: WKNavigationAction,
30        windowFeatures: WKWindowFeatures
31    ) -> WKWebView? {
32        if navigationAction.targetFrame == nil {
33            webView.load(navigationAction.request)
34        }
35        return nil
36    }
37}

This tells WebKit, "do not create a second view; load the request here instead."

Opening in a Separate In-App Browser

Sometimes loading the new page in the same view is not the desired behavior. You may want a modal browser, a dedicated tab, or an external Safari handoff.

The same delegate method gives you that control. For example, you can present SFSafariViewController for links that should leave the embedded experience.

swift
1import SafariServices
2import WebKit
3
4final class BrowserDelegate: NSObject, WKUIDelegate {
5    weak var presenter: UIViewController?
6
7    func webView(
8        _ webView: WKWebView,
9        createWebViewWith configuration: WKWebViewConfiguration,
10        for navigationAction: WKNavigationAction,
11        windowFeatures: WKWindowFeatures
12    ) -> WKWebView? {
13        guard navigationAction.targetFrame == nil,
14              let url = navigationAction.request.url,
15              let presenter else {
16            return nil
17        }
18
19        let safari = SFSafariViewController(url: url)
20        presenter.present(safari, animated: true)
21        return nil
22    }
23}

This is often the cleanest solution when the content should behave more like a real browser session.

Many developers first notice the issue with anchor tags, but the same idea applies to JavaScript popups. Both patterns request a new browsing context.

If the page depends on popup behavior, you may also need to review WKPreferences and how JavaScript-initiated windows should be handled in your app. Even then, the key architectural point stays the same: your code must decide what a new window means in your UI.

When the Delegate Still Does Not Fire

If your handler is not called, check the basics first.

  • make sure uiDelegate is assigned on the exact WKWebView instance being displayed
  • verify the page really uses target="_blank" or window.open
  • confirm the link is not prevented by page JavaScript before navigation occurs
  • test with a minimal inline HTML example before blaming the site

It is also useful to implement a navigation delegate and log requests so you can see whether the page is attempting normal same-frame navigation or a new-window request.

Common Pitfalls

The most common mistake is implementing only WKNavigationDelegate and expecting it to handle new windows automatically. Same-frame navigation and new-window creation are different delegate paths.

Another mistake is returning a new WKWebView without retaining or presenting it. If you create one and immediately lose the reference, nothing visible happens.

A third issue is forcing every blank-target link into the same view without considering user experience. Login flows, payment pages, and external documents may behave better in Safari or a dedicated modal browser.

Summary

  • 'WKWebView does not automatically open target="_blank" links.'
  • New-window requests are handled through WKUIDelegate, not just navigation delegate methods.
  • The common fix is to detect targetFrame == nil and load the request manually.
  • You can also open the URL in a new WKWebView or SFSafariViewController.
  • If nothing fires, verify that uiDelegate is assigned correctly.
  • Treat blank-target links as a UI decision your app must make explicitly.

Course illustration
Course illustration

All Rights Reserved.