# How to handle popups and alerts in WKWebView

In this blog post, I'll explain how you can support popups and alerts in WKWebView because this is not supported out of the box.

## Default behavior

The following cases **do not work** in a `WKWebView` **automatically**:
- opening a new tab/window with `<a>` HTML element with attribute `target="_blank"`
- opening a JavaScript alert by clicking on an `<a>` HTML element with `href="javascript:alert('Hello World!');"`
- opening a new window with Javascript and DOM's `window.open` and window.close` functions

You can verify that yourself by using this HTML page to manually test the three use cases.

```html
<!DOCTYPE html>
<html>
   <body>
      <h1>WKWebView and WKUIDelegate</h1>

      <h2>Testing a href with target="_blank"</h2>
      <a href="https://www.google.com" target="_blank">Visit Google</a>

      <h2>Testing a href with javascript:alert</h2>
      <a href="javascript:alert('Hello World!');">Execute JavaScript</a>

      <h2>Testing window.open() and window.close() Methods</h2>
      <button onclick="openWin()">Open "myWindow" which will be closed after 3 seconds</button>
      <script>

         function openWin() {
           myWindow = window.open("https://www.apple.com", "", "width=200,height=100");
           setTimeout(function() { myWindow.close() }, 3000);
         }
         
      </script>
   </body>
</html>
```

We start with a `WKWebView` without any delegate implementation.

```Swift
let webView = WKWebView()
```

And let's load the HTML page, which can be bundled as a resource in an iOS application.

```Swift
if let url = Bundle.main.url(forResource: "local", withExtension: "html") {
  webView.loadFileURL(url, allowingReadAccessTo: url.deletingLastPathComponent())
}
```

Clicking on any other links or buttons has no effect.


![Doesn't work without delegate implementation](https://cdn.hashnode.com/res/hashnode/image/upload/v1666218287913/6ci4ozLJY.gif align="left")

Why is that?

## Introducing WKUIDelegate

> **The default web view implementation assumes one window per web view, so nonconventional user interfaces might implement a user interface delegate.**

This quote is from the [`WKUIDelegate`](https://developer.apple.com/documentation/webkit/wkuidelegate) documentation.

`WKUIDelegate` is a protocol with several optional functions that can be implemented.

> Web view user interface delegates implement this protocol to control the opening of new windows, augment the behavior of default menu items displayed when the user clicks elements, and perform other user interface-related tasks. These methods can be invoked as a result of handling JavaScript or other plug-in content.

```Swift
extension ViewController: WKUIDelegate {}
```

```Swift
let webView = WKWebView()
webView.uiDelegate = self // or whoever conforms to WKUIDelegate protocol 
```

## Handle static HTML links

Let's implement the first function: [`webView(_:createWebViewWith:for:windowFeatures:)`](https://developer.apple.com/documentation/webkit/wkuidelegate/1536907-webview)

> If you do not implement this method, the web view will cancel the navigation.

A rudimentary implementation can be that such links are opened in the Safari app.

```Swift
func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
    if navigationAction.targetFrame == nil {
        UIApplication.shared.open(navigationAction.request.url!, options: [:])
    }
    return nil
}
```

Later comes a more sophisticated example to allow handling navigation actions with the app itself. So keep on reading :)

## JavaScript alerts

First, you have to configure your WKWebView to allow JavaScript !!

```Swift
let webView = WKWebView()
webView.uiDelegate = self
webView.configuration.preferences.javaScriptEnabled = true // !!
```

Then it's time to implement one of the `runJavascript` related functions in `WKUIDelegate`.

For the test case above the function [`webView(_:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:)`](https://developer.apple.com/documentation/webkit/wkuidelegate/1537406-webview) needs to be implemented.

```Swift
func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {
        let ac = UIAlertController(title: nil,
                                   message: message,
                                   preferredStyle: .alert)
        ac.addAction(UIAlertAction(title: "Ok",
                                   style: .default) { _ in
            completionHandler()
        })
        present(ac, animated: true)
}
```

## JavaScript popups

First, you have to configure your WKWebView that JavaScript can open windows !!

```Swift
let webView = WKWebView()
webView.uiDelegate = self
webView.configuration.preferences.javaScriptEnabled = true
webView.configuration.preferences.javaScriptCanOpenWindowsAutomatically = true // !!
```

|JavaScript|Triggered `WKUIDelegate` function|
|---|---|
|`window.open()`|`webView(_:createWebViewWith:for:windowFeatures:)`|
|`window.close()`|[`webViewDidClose(_:)`](https://developer.apple.com/documentation/webkit/wkuidelegate/1537390-webviewdidclose)|

You can achieve an in-app popup experience by implementing those two delegate functions and managing multiple `WKWebInstances`. For more details and an example project please check out the following GitHub repository:

%[https://github.com/alwaysSwift/wkwebview-with-popup]

## Conclusion

You can support popups and alerts in a `WKWebView` by implementing`WKUIDelegate`.

![Working with delegate implementation](https://cdn.hashnode.com/res/hashnode/image/upload/v1666218315130/Vf-gFZk0b.gif align="left")



