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.
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.
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).
' 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
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
' --- 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("\", "/")}")
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.
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.
' --- 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
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.
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.
' --- 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
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.
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.
' --- 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; ' });
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.
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.
' --- 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
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.
23.7 GitHub Copilot — WebView2 Patterns
' 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
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
WebBrowsercontrol. WebView2 uses Chromium Edge and supports all modern web standards. - Always
Await wvBrowser.EnsureCoreWebView2Async()inForm_Loadbefore accessingCoreWebView2members. Mark the Sub asAsync. - Navigate with
wvBrowser.CoreWebView2.Navigate(url)or setwvBrowser.Source = New Uri(url). Load local HTML directly withNavigateToString(htmlString). NavigationStarting: fires before loading, sete.Cancel = Trueto block.NavigationCompleted: fires when done, checke.IsSuccessand update the URL bar / status.Await wvBrowser.ExecuteScriptAsync("js code")runs JavaScript in the page and returns a JSON-encoded string. UseSystem.Text.Json.JsonSerializer.Deserializeto parse complex results.- Two-way messaging: page → VB via
window.chrome.webview.postMessage()received inWebMessageReceived; VB → page viaCoreWebView2.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.Settingsand 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 callsExecuteScriptAsync("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.WriteAllTextand open it in the default browser withProcess.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
postMessageand process it inWebMessageReceived - VB sends results back with
PostWebMessageAsStringto update the page dynamically - Use
NavigationStartingto block all external URLs — allow onlyabout:blankand 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)"
Related Resources
← Lesson 22
RadioButton — mutually exclusive selections.
Lesson 24 →
Error Handling — Try/Catch/Finally.
MS Docs — WebView2
Complete WebView2 documentation, samples, and API reference.
WebView2 WinForms Quickstart
Official getting-started guide for WinForms + WebView2.
Featured Books
Visual Basic 2022 Made Easy
Web browser integration and all major WinForms controls covered with complete examples.
View on Amazon →
VB Programming With Code Examples
48 complete programs including web-integrated and data-driven applications.
View on Amazon →