Lesson 23 · Web Browser Control

The WebView2 Control

Embed a full Chromium-based browser inside your VB 2026 application using Microsoft's WebView2 control — navigate URLs, handle navigation events, execute JavaScript from VB, receive messages from web pages, inject CSS, and build a complete mini-browser with toolbar and history.

Key Takeaway: In VB 2026, use the Microsoft.Web.WebView2 NuGet package, not the old WebBrowser control. WebView2 is based on Chromium Edge and supports modern HTML5, CSS3, and JavaScript. The three essential steps are: (1) add the NuGet package, (2) Await wv.EnsureCoreWebView2Async() in Form_Load before using any WebView2 features, and (3) use wv.Source or wv.CoreWebView2.Navigate(url) to load pages. All navigation, JavaScript execution, and message-passing use Async/Await — mark your handlers Async when using them.
Source
Uri (Property)
Get or set the current page URL. Setting this navigates to that address.
CoreWebView2.Navigate()
Method
Navigate to a URL string. Use after EnsureCoreWebView2Async completes.
EnsureCoreWebView2Async()
Async Method
Initialise the browser engine. Must Await this before calling CoreWebView2 members.
ExecuteScriptAsync()
Async Method
Run JavaScript in the page and get the return value as a JSON string.
NavigationCompleted
Event
Fires when navigation finishes (success or failure). Check IsSuccess.
NavigationStarting
Event
Fires before navigation begins. Set e.Cancel = True to block a URL.
WebMessageReceived
Event
Fires when page JavaScript calls window.chrome.webview.postMessage().
CoreWebView2.GoBack/Forward()
Methods
Navigate back/forward in history. Check CanGoBack / CanGoForward first.

23.1 Setup — Installing WebView2

The old WebBrowser control (based on IE) is obsolete. WebView2 is the modern replacement, shipping Chromium Edge inside your app. You need two things: the NuGet runtime package, and the WebView2 runtime installed on the user's machine (pre-installed on all Windows 11 machines).

Setup — NuGet + Designer
' Step 1: Install the NuGet package
' In Visual Studio: Tools → NuGet Package Manager → Manage NuGet Packages
' Search: Microsoft.Web.WebView2
' Install the latest stable version (2.0.x or later)

' Step 2: Add to the Toolbox
' After installing, WebView2 appears in the Toolbox.
' Drag it onto your form like any other control.
' Rename it: wvBrowser (or wv, webView, etc.)

' Step 3: Imports at top of form code
Imports Microsoft.Web.WebView2.WinForms
Imports Microsoft.Web.WebView2.Core

' Step 4: Initialise in Form_Load — ALWAYS Await this first!
Private Async Sub Form1_Load(...) Handles MyBase.Load
    Await wvBrowser.EnsureCoreWebView2Async()   ' starts the browser engine
    wvBrowser.Source = New Uri("https://www.vbtutor.net")
End Sub

' Alternatively, set a home page from settings
Private Async Sub Form1_Load(...) Handles MyBase.Load
    Await wvBrowser.EnsureCoreWebView2Async()
    Dim homePage = My.Settings.HomePage
    If String.IsNullOrWhiteSpace(homePage) Then
        homePage = "https://www.google.com"
    End If
    wvBrowser.CoreWebView2.Navigate(homePage)
End Sub
Always Await EnsureCoreWebView2Async First

If you call CoreWebView2.Navigate() or ExecuteScriptAsync() before EnsureCoreWebView2Async() completes, you will get a NullReferenceException because CoreWebView2 is Nothing until initialisation finishes. Always Await wv.EnsureCoreWebView2Async() before using any CoreWebView2 member. Mark the containing Sub as Async.


23.2 Navigation — Source, Navigate, Back, Forward, Reload

Navigation.vb — Visual Basic 2026
' --- Navigate to a URL ---
Private Sub btnGo_Click(...) Handles btnGo.Click
    Dim url = txtUrl.Text.Trim()
    If Not url.StartsWith("http") Then url = "https://" & url
    wvBrowser.CoreWebView2.Navigate(url)
End Sub

' Navigate when user presses Enter in the URL bar
Private Sub txtUrl_KeyDown(...) Handles txtUrl.KeyDown
    If e.KeyCode = Keys.Enter Then btnGo.PerformClick()
End Sub

' --- Back / Forward / Reload / Home ---
Private Sub btnBack_Click(...) Handles btnBack.Click
    If wvBrowser.CoreWebView2.CanGoBack Then
        wvBrowser.CoreWebView2.GoBack()
    End If
End Sub

Private Sub btnForward_Click(...) Handles btnForward.Click
    If wvBrowser.CoreWebView2.CanGoForward Then
        wvBrowser.CoreWebView2.GoForward()
    End If
End Sub

Private Sub btnReload_Click(...) Handles btnReload.Click
    wvBrowser.CoreWebView2.Reload()
End Sub

Private Sub btnHome_Click(...) Handles btnHome.Click
    wvBrowser.CoreWebView2.Navigate("https://www.vbtutor.net")
End Sub

' --- NavigationCompleted — update UI after page loads ---
Private Sub wvBrowser_NavigationCompleted(...) Handles wvBrowser.NavigationCompleted
    If e.IsSuccess Then
        txtUrl.Text = wvBrowser.Source.ToString()
        lblStatus.Text = $"Loaded: {wvBrowser.CoreWebView2.DocumentTitle}"
    Else
        lblStatus.Text = $"Error: {e.WebErrorStatus}"
    End If
    btnBack.Enabled    = wvBrowser.CoreWebView2.CanGoBack
    btnForward.Enabled = wvBrowser.CoreWebView2.CanGoForward
End Sub

' --- Load local HTML content (no web server needed) ---
wvBrowser.NavigateToString("<h1>Hello from VB!</h1><p>Local HTML.</p>")

' --- Load a local file ---
Dim htmlPath = Path.Combine(Application.StartupPath, "report.html")
wvBrowser.CoreWebView2.Navigate($"file:///{htmlPath.Replace("\", "/")}")
Try It — Simulation 23.1: Mini Browser with Navigation

A simulated browser toolbar demonstrating Back, Forward, Reload, Home, and URL navigation. The VB trace shows which CoreWebView2 calls would fire in a real app.

MiniBrowser — Form1.vb [WebView2]
Ready

23.3 NavigationStarting — Blocking URLs

The NavigationStarting event fires before any page loads. Setting e.Cancel = True prevents navigation. This is how you build content filters, parental controls, or corporate web proxies that block blacklisted domains.

UrlFilter.vb — Visual Basic 2026
' --- Blocked domains list ---
Private ReadOnly _blockedDomains As String() = {
    "facebook.com", "twitter.com", "tiktok.com", "youtube.com"
}

Private Sub wvBrowser_NavigationStarting(...) Handles wvBrowser.NavigationStarting
    Dim url = e.Uri.ToLower()

    ' Block listed domains
    For Each domain In _blockedDomains
        If url.Contains(domain) Then
            e.Cancel = True
            lblStatus.Text = $"Blocked: {domain}"
            wvBrowser.NavigateToString(
                $"<h2 style='color:red'>Access Blocked</h2>
                  <p>{domain} is not allowed on this device.</p>")
            Return
        End If
    Next

    ' Allow only HTTPS in production mode
    If chkHttpsOnly.Checked AndAlso Not url.StartsWith("https://") Then
        e.Cancel = True
        lblStatus.Text = "Blocked: HTTP not allowed (HTTPS only mode)"
        Return
    End If

    ' Show the URL being visited in the toolbar
    txtUrl.Text = e.Uri
    lblStatus.Text = $"Loading: {e.Uri}"
End Sub
Try It — Simulation 23.2: URL Filter / Content Blocker

Enter a URL and click Navigate. The NavigationStarting filter checks it against a blocklist and the HTTPS-only toggle. Blocked URLs show a red alert; allowed ones load in the viewport.

Content Filter — NavigationStarting Demo
URL to navigate:
Blocked: facebook.com, twitter.com, tiktok.com, youtube.com
Ready

23.4 ExecuteScriptAsync — Running JavaScript from VB

ExecuteScriptAsync lets your VB code reach into the loaded web page and run any JavaScript. The return value comes back as a JSON-encoded string. This is how you scrape page data, manipulate the DOM, scroll, click elements, or inject custom behaviour into any web page.

ExecuteScript.vb — Visual Basic 2026
' --- Get the page title ---
Private Async Sub btnGetTitle_Click(...) Handles btnGetTitle.Click
    Dim result = Await wvBrowser.ExecuteScriptAsync("document.title")
    ' Result is JSON-encoded: "\"VBTutor - Visual Basic Tutorial\""
    lblTitle.Text = result.Trim(""""c)   ' strip surrounding quotes
End Sub

' --- Get all link hrefs on the page ---
Private Async Sub btnGetLinks_Click(...) Handles btnGetLinks.Click
    Dim script = "JSON.stringify(Array.from(document.links).map(a => a.href))"
    Dim json   = Await wvBrowser.ExecuteScriptAsync(script)
    ' json = '["https://...","https://..."]'
    Dim links  = System.Text.Json.JsonSerializer.Deserialize(Of String())(json)
    lstLinks.Items.Clear()
    For Each link In links
        lstLinks.Items.Add(link)
    Next
End Sub

' --- Scroll the page ---
Private Async Sub btnScrollDown_Click(...) Handles btnScrollDown.Click
    Await wvBrowser.ExecuteScriptAsync("window.scrollBy(0, 400)")
End Sub

' --- Inject CSS: hide ads / dark mode ---
Private Async Sub InjectDarkMode()
    Dim css = "html{filter:invert(1) hue-rotate(180deg)!important}"
    Dim script = $"var s=document.createElement('style');s.textContent='{css}';document.head.appendChild(s)"
    Await wvBrowser.ExecuteScriptAsync(script)
End Sub

' --- Fill a form field programmatically ---
Private Async Sub AutoFillSearch(query As String)
    Dim script = $"document.querySelector('input[name=""q""]').value = '{query}'"
    Await wvBrowser.ExecuteScriptAsync(script)
End Sub

' --- Get computed style value ---
Private Async Sub btnGetBgColor_Click(...) Handles btnGetBgColor.Click
    Dim color = Await wvBrowser.ExecuteScriptAsync(
        "getComputedStyle(document.body).backgroundColor")
    lblBgColor.Text = color.Trim(""""c)
End Sub
Try It — Simulation 23.3: JavaScript Executor

Enter any JavaScript expression. The simulation runs it against a fake "loaded page" state and shows the VB ExecuteScriptAsync call and the JSON-encoded return value — just as a real WebView2 would return it.

JavaScript Executor — ExecuteScriptAsync Demo
JavaScript expression:

23.5 WebMessageReceived — JS to VB Communication

Web pages can send messages back to your VB app by calling window.chrome.webview.postMessage(data) in JavaScript. VB receives this in the WebMessageReceived event. This is how you build hybrid apps: rich HTML/JS UI in the browser pane, business logic in VB.

WebMessage.vb — Visual Basic 2026
' --- VB side: listen for messages from the web page ---
Private Sub Form1_Load(...) Handles MyBase.Load
    Await wvBrowser.EnsureCoreWebView2Async()
    AddHandler wvBrowser.CoreWebView2.WebMessageReceived, AddressOf OnWebMessage
    wvBrowser.NavigateToString(GetPageHtml())
End Sub

Private Sub OnWebMessage(sender As Object, e As CoreWebView2WebMessageReceivedEventArgs)
    Dim msg = e.TryGetWebMessageAsString()   ' simple string message

    ' Or parse JSON: Dim json = e.WebMessageAsJson
    Select Case msg
        Case "btn_clicked" : lblInfo.Text = "User clicked the web button!"
        Case "form_submit" : ProcessWebForm(e.WebMessageAsJson)
        Case Else         : lstLog.Items.Add($"Message: {msg}")
    End Select
End Sub

' --- HTML page side: send message to VB app ---
Private Function GetPageHtml() As String
    Return "<!DOCTYPE html><html><body>
      <h2>Hybrid App Page</h2>
      <button onclick=""window.chrome.webview.postMessage('btn_clicked')"">
        Send Message to VB
      </button>
      <input id='name' placeholder='Your name'>
      <button onclick=""window.chrome.webview.postMessage(
         JSON.stringify({action:'greet', name: document.getElementById('name').value})
      )"">Send Name</button>
    </body></html>"
End Function

' --- VB sends a message TO the web page ---
Private Sub btnSendToPage_Click(...) Handles btnSendToPage.Click
    Dim payload = $"{{""type"":""update"", ""value"":""{txtSend.Text}""}}"
    wvBrowser.CoreWebView2.PostWebMessageAsString(payload)
End Sub

' On the HTML/JS side, receive it:
' window.chrome.webview.addEventListener("message", e => {
'   document.getElementById("output").textContent = e.data;
' });
Try It — Simulation 23.4: Hybrid App — JS ↔ VB Messaging

Simulates a web page running inside WebView2. Click the web-side button to send a message to "VB". Type in the VB input and click Send to inject a message into the "page". The log shows all messages in both directions.

Hybrid App — WebMessageReceived Demo
🌐 Web Page (HTML/JS)
Interactive page loaded in WebView2:
Waiting for VB message...
◆ VB App (WinForms)
lblInfo:
(waiting for web message)
PostWebMessageAsString:
Message log:

23.6 NavigateToString — Local HTML Reports

You don't need a web server — use NavigateToString() to load HTML built entirely in VB strings. This is perfect for generating formatted reports, previewing invoices, or displaying help content that you style with CSS.

LocalHTML.vb — Visual Basic 2026
' --- Build an HTML report from a data table ---
Private Function BuildSalesReport(sales As DataTable) As String
    Dim sb As New Text.StringBuilder
    sb.AppendLine("<!DOCTYPE html><html><head>")
    sb.AppendLine("<style>
      body{font-family:Segoe UI,sans-serif;padding:20px;}
      h1{color:#1a3a6b;}
      table{border-collapse:collapse;width:100%;}
      th{background:#1a3a6b;color:#fff;padding:8px 12px;text-align:left;}
      td{padding:7px 12px;border-bottom:1px solid #eee;}
      tr:nth-child(even){background:#f5f7fa;}
      .total{font-weight:bold;background:#e8f4ff!important;}
    </style></head><body>")
    sb.AppendLine($"<h1>Sales Report — {DateTime.Now:dd MMM yyyy}</h1>")
    sb.AppendLine("<table><tr><th>Product</th><th>Units</th><th>Revenue</th></tr>")

    Dim grandTotal = 0D
    For Each row As DataRow In sales.Rows
        Dim rev = CDec(row("Revenue"))
        grandTotal += rev
        sb.AppendLine($"<tr><td>{row("Product")}</td>
                           <td>{row("Units"):N0}</td>
                           <td>{rev:C2}</td></tr>")
    Next
    sb.AppendLine($"<tr class='total'><td>TOTAL</td><td></td>
                       <td>{grandTotal:C2}</td></tr>")
    sb.AppendLine("</table></body></html>")
    Return sb.ToString()
End Function

' Display in WebView2
Private Sub btnPreview_Click(...) Handles btnPreview.Click
    wvBrowser.NavigateToString(BuildSalesReport(dtSales))
End Sub

' Print directly from WebView2
Private Async Sub btnPrint_Click(...) Handles btnPrint.Click
    Await wvBrowser.ExecuteScriptAsync("window.print()")
End Sub
Try It — Simulation 23.5: HTML Report Generator

Edit the sales data, click Generate Report, and the VB code builds a styled HTML table and loads it via NavigateToString(). The full HTML source is shown below the preview.

HTML Report Generator — NavigateToString
Sales data (name, units, price):

23.7 GitHub Copilot — WebView2 Patterns

GitHub Copilot — Full Mini Browser
You typed: ' Build a complete mini browser form with WebView2. Include: URL bar, back/forward/reload/home buttons, favourites list (ListBox), bookmark button, status bar showing page title and load state, NavigationStarting HTTPS-only filter, and history tracking in a List(Of String).'
' Complete mini browser with history, favourites and security filter.
Imports Microsoft.Web.WebView2.WinForms
Imports Microsoft.Web.WebView2.Core

Public Class MiniBrowser
    Private _history As New List(Of String)
    Private Const HOME_URL = "https://www.vbtutor.net"

    Private Async Sub MiniBrowser_Load(...) Handles MyBase.Load
        Await wvBrowser.EnsureCoreWebView2Async()
        AddHandler wvBrowser.CoreWebView2.WebMessageReceived, AddressOf OnWebMessage
        wvBrowser.CoreWebView2.Navigate(HOME_URL)
    End Sub

    Private Sub wvBrowser_NavigationStarting(...) Handles wvBrowser.NavigationStarting
        lblStatus.Text = $"Loading: {e.Uri}"
        If chkHttpsOnly.Checked AndAlso Not e.Uri.StartsWith("https") Then
            e.Cancel = True
            lblStatus.Text = "Blocked: HTTPS only"
        End If
    End Sub

    Private Sub wvBrowser_NavigationCompleted(...) Handles wvBrowser.NavigationCompleted
        Dim url = wvBrowser.Source.ToString()
        txtUrl.Text  = url
        lblStatus.Text = If(e.IsSuccess,
            $"\u2714 {wvBrowser.CoreWebView2.DocumentTitle}",
            $"\u2716 Error {e.WebErrorStatus}")
        btnBack.Enabled    = wvBrowser.CoreWebView2.CanGoBack
        btnForward.Enabled = wvBrowser.CoreWebView2.CanGoForward
        If e.IsSuccess AndAlso Not _history.Contains(url) Then
            _history.Add(url)
            lstHistory.Items.Add(url)
        End If
    End Sub

    Private Sub btnBookmark_Click(...) Handles btnBookmark.Click
        Dim url = wvBrowser.Source.ToString()
        If Not lstFavourites.Items.Contains(url) Then
            lstFavourites.Items.Add(url)
            My.Settings.Favourites.Add(url)
            My.Settings.Save()
        End If
    End Sub

    Private Sub lstFavourites_DoubleClick(...) Handles lstFavourites.DoubleClick
        If lstFavourites.SelectedItem IsNot Nothing Then
            wvBrowser.CoreWebView2.Navigate(lstFavourites.SelectedItem.ToString())
        End If
    End Sub
End Class
Copilot Chat Prompts for This Lesson

Try these in the Copilot Chat panel while working with WebView2:

  • "Write an Async Sub that uses ExecuteScriptAsync to extract all image src attributes from the current page and populate a ListBox"
  • "Create a download manager: handle CoreWebView2.DownloadStarting event, show a ProgressBar, and save to a user-selected folder"
  • "Build a screen scraper: navigate to a URL, wait for NavigationCompleted, then use ExecuteScriptAsync to extract the innerText of all h2 tags"
  • "Inject a floating toolbar into any web page using ExecuteScriptAsync that adds VB-controlled bookmarks and highlights"

Lesson Summary

  • Use the Microsoft.Web.WebView2 NuGet package, not the obsolete WebBrowser control. WebView2 uses Chromium Edge and supports all modern web standards.
  • Always Await wvBrowser.EnsureCoreWebView2Async() in Form_Load before accessing CoreWebView2 members. Mark the Sub as Async.
  • Navigate with wvBrowser.CoreWebView2.Navigate(url) or set wvBrowser.Source = New Uri(url). Load local HTML directly with NavigateToString(htmlString).
  • NavigationStarting: fires before loading, set e.Cancel = True to block. NavigationCompleted: fires when done, check e.IsSuccess and update the URL bar / status.
  • Await wvBrowser.ExecuteScriptAsync("js code") runs JavaScript in the page and returns a JSON-encoded string. Use System.Text.Json.JsonSerializer.Deserialize to parse complex results.
  • Two-way messaging: page → VB via window.chrome.webview.postMessage() received in WebMessageReceived; VB → page via CoreWebView2.PostWebMessageAsString().
  • NavigateToString(html) loads raw HTML without a server — ideal for generating styled reports, invoices, and help content entirely from VB string-building code.

Exercises

Exercise 23.1 — Personal Mini Browser

  • Build a form with WebView2, URL bar, Back/Forward/Reload/Home buttons, and a status bar
  • Implement history in a ListBox; double-clicking a history item navigates to it
  • Add a Bookmarks menu (MenuStrip) that saves URLs to My.Settings and loads them on startup
  • Show a loading spinner Label while navigation is in progress (hide on NavigationCompleted)
  • Copilot challenge: Ask Copilot to "add a Find-on-Page feature using ExecuteScriptAsync with window.find() and highlight all matches"

Exercise 23.2 — Sales Report Viewer

  • Load sales data from a DataGridView or database table
  • Build an HTML report with NavigateToString: styled table, chart using inline SVG, and a print button that calls ExecuteScriptAsync("window.print()")
  • Add a filter: RadioButtons for Monthly / Quarterly / Annual — rebuild the HTML on selection
  • Export: Save the generated HTML to a file using File.WriteAllText and open it in the default browser with Process.Start
  • Copilot challenge: Ask Copilot to "generate a bar chart using inline SVG based on the DataTable values"

Exercise 23.3 — Hybrid Dashboard

  • Load a local HTML file with a form (text inputs, buttons, dropdowns)
  • When the user submits the HTML form, send data to VB via postMessage and process it in WebMessageReceived
  • VB sends results back with PostWebMessageAsString to update the page dynamically
  • Use NavigationStarting to block all external URLs — allow only about:blank and local file paths
  • Copilot challenge: Ask Copilot to "serialize the WebMessageReceived JSON payload to a custom Class using System.Text.Json.JsonSerializer.Deserialize(Of MyClass)"

Next: Lesson 24 — Error Handling

Learn robust error handling in VB 2026 — Try/Catch/Finally, the Exception class hierarchy, custom exceptions, and structured error logging to prevent your app from crashing.

Continue »

Related Resources


Featured Books

Visual Basic 2022 Made Easy

Visual Basic 2022 Made Easy

by Dr. Liew Voon Kiong

Web browser integration and all major WinForms controls covered with complete examples.

View on Amazon →
VB Programming With Code Examples

VB Programming With Code Examples

by Dr. Liew Voon Kiong

48 complete programs including web-integrated and data-driven applications.

View on Amazon →