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 →
Visual Basic 2026 Made Easy
From fundamentals to advanced projects, Visual Basic 2026 Made Easy covers database apps, REST APIs, custom graphics, and responsive UIs—all using .NET 10 and GitHub Copilot.
View on Amazon →