| page_type | urlFragment | products | languages | extensions | description | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
sample |
word-hybrid-blazor-add-in |
|
|
|
Create a Hybrid Blazor Word add-in showcasing some samples. |
This sample shows how to build a Word add-in using .NET Blazor Hybrid technologies. Blazor WebAssembly allows you to build Office Add-ins using .NET, C#, and JavaScript to interact with the Office JS API. The add-in uses JavaScript to work with the document and Office JS APIs, but you build the user interface and all other non-Office interactions in C# and .NET Core Blazor technologies.
- Work with Hybrid Blazor Webassembly in the context of Office.
- Build cross-platform Office Add-ins using Hybrid Blazor, C# and JavaScript Interop.
- Initialize the Office JavaScript API library in Hybrid Blazor context.
- Interact with Word to manipulate Documents.
- Interact with document content through Office JavaScript APIs.
- Interact with methods defined on the Hybrid Blazor Pages.
- Interop between OfficeJS - JavaScript - C# and back to JavaScript.
- Word on the web, Windows, and Mac.
- Microsoft 365 - Get a free developer sandbox that provides a renewable 90-day Microsoft 365 E5 developer subscription.
- Download or clone the Office Add-ins samples repository.
- Open Visual Studio 2022 and open the: Office-Add-in-samples\Samples\blazor-add-in\Blazor.Word.AddIn\Blazor.Word.AddIn.sln solution.
- Choose Debug > Start Debugging. Or press F5 to start the solution and sideload the Add-in and start Word.
- [Optionally] You can use the Terminal to sideload the Add-in and start Word using the command npm run start-local separately
- When Word opens, choose Sample Add-in > Show task pane (if not already open).
- Try out the controls on the task panes.
- Try out the custom buttons on the Sample Add-in tab on the ribbon.
An Office Add-in is a web application that extends Office with additional functionality for the user. For example, an add-in can add ribbon buttons, a task pane, or a content pane with the functionality you want. Because an Office Add-in is a web application, you must provide a web server to host the files.
Building the Office Add-in as a Hybrid Blazor Application it allows you to build a .NET Core compliant website that interacts with the Office JS APIs using WebAssembly. If your background is with VBA, VSTO, or COM add-in development, you may find that building Office Add-ins using Hybrid Blazor is a familiar development technique.
By using Hybrid Blazor, you can select which parts of your add-in you want to build in C# and which parts you want to build in TypeScript. This allows you to leverage the strengths of both languages and build a more robust add-in that can run parts that need a higher security level at the server and only bring the parts that interact with Office to the client.
This sample also implemented the Blazor Fluent UI components to show how you can use the Fluent UI components in your add-in. The Blazor Fluent UI components are a set of UI components that implement the Fluent Design System. The Fluent UI components contains options to easily implement Themes to your Add-in. To switch between themes select the Theme option in the Ribbon, or the Theme option in the task pane menu.
This sample also implemented TypeScript as a language to interact with the Office JS API. TypeScript is a superset of JavaScript that transpiles to plain JavaScript. TypeScript is designed for the development of large applications and can be used to develop Office Add-ins. TypeScript is a language that is easy to learn and can be used to build Office Add-ins that interact with the Office JS API. TypeScript allows you to develop strong typed code that can detect compile-time issues before the code is deployed where often JavaScript issues only are discovered at runtime in production.
This sample runs a Hybrid Blazor Application that runs cross-platform in various browsers supporting WASM (WebAssembly). The part that is using WebAssembly demonstrates some basic Word functions using the Document.
The purpose of this sample is to show you how to build and interact with the Blazor, C# and JavaScript Interop options. If you're looking for more examples of interacting with Word and Office JS APIs, see Script Lab.
The Pages folder contains the Blazor pages, and is based on the generic Blazor demo application provided in Visual Studio. It contains similar pages such as Home, Counter and Weather. The Home page is implemented as Home.razor. As pages can run both on the Server side or the Client side they can be defined in either the Add-in project or the Client project.
Each .razor page can contain code-behind pages, for example, named Home.razor.cs and Home.razor.ts. The C# file first establishes an interop connection with the JavaScript file (generated by TypeScript).
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
try
{
await JSHost.ImportAsync("Home", "../Pages/Home.razor.js");
Console.WriteLine($"Imported Home module");
}
catch (Exception ex)
{
Console.WriteLine($"Error importing Home module: {ex.Message}");
}
HostInformation = await OfficeUtilities.IsRunningInHostAsync();
Console.WriteLine($"Home HostInformation: {HostInformation}");
if (HostInformation)
{
StateHasChanged();
}
}
}For any events that need to interact with the Office document, the C# file calls through interop to the JavaScript (generated by TypeScript) file.
[JSImport("insertParagraph", "Home")]
internal static partial Task InsertParagraph();The JavaScript runs the code to interact with the document and returns.
export async function insertParagraph() {
console.log("We are now entering function: insertParagraph");
try {
await Word.run(async function (context) {
// Inserts a paragraph at the start of the document.
context.document.body.insertParagraph(
"Hello World from Blazor",
Word.InsertLocation.start
);
});
} catch (error) {
console.error("Error creating welcome home: ", error);
}
}The fundamental pattern includes the following steps.
- Call JSImport to set up the interop between C# and JavaScript.
- This hooks up the C# method to the JavaScript method.
- Call Office JS APIs to interact with the document from JavaScript code.
This sample shows how to use Blazor with custom buttons on the ribbon. The buttons call the same functions that are defined on the task pane. This sample is configured to use the shared runtime which is required for this interop to work correctly.
This sample is configured to support debugging both JavaScript and C# files. New Blazor projects need the following file updates to support C# debugging.
- In the launchSettings.json file of the web project, make sure all instances of
launchBrowserare set tofalse. - In the .csproj.user file of the add-in project, add the
<BlazorAppUrl>and<InspectUri>elements as shown in the following example XML.
Note: The port number in the following XML is 7215. You must change it to the port number specified in the launchSettings.json file for your web project.
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<BlazorAppUrl>https://localhost:7215/</BlazorAppUrl>
<InspectUri>{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}</InspectUri>
</PropertyGroup>
</Project>This repo includes VS Code task and launch configurations under the .vscode folder to build, run, sideload and debug the add-in from VS Code.
- Build and restore (tasks or CLI):
dotnet restore .\Blazor.Word.AddIn.sln
dotnet build .\Blazor.Word.AddIn.sln -c Debug-
Run the server, sideload the add-in, and attach the debugger (recommended):
- Open the Run view in VS Code and select the
Sideload & Attach (server)configuration, then press F5. - That configuration runs a composite pre-launch task named
Start: Server & Sideloadwhich performs the sequence below:- Starts the
Run: Servertask as a background process (dotnet runfor theBlazor.Word.AddInproject). - Waits for the server to signal readiness (background problem matcher).
- Runs the
Sideload: start-localtask (which executesnpm run start-localin theBlazor.Word.AddInfolder) to sideload the manifest into Word.
- Starts the
- After the pre-launch task finishes, VS Code will prompt you to pick the running
.NETprocess to attach the debugger to — choose theBlazor.Word.AddInprocess. - This flow ensures the server is up before sideloading runs and avoids starting a second server instance (prevents port-binding conflicts).
- Open the Run view in VS Code and select the
dotnet: Restoredotnet: Build SolutionStart: Server & Sideload(sequencesRun: ServerthenSideload: start-local)Run: Server(background — runsdotnet runfor theBlazor.Word.AddInproject)Sideload: start-local(runsnpm run start-localinBlazor.Word.AddIn)npm: Install (All)(composite: runs both installs in parallel)npm: Install (Blazor Server)(runsnpm installin the server folder)npm: Install (Blazor Client)(runsnpm installin the client folder)
Terminal behavior:
- The server, sideload and npm install tasks are configured to run in dedicated VS Code terminal panels so their outputs remain separated and easier to monitor.
- Use the Command Palette (
Ctrl+Shift+P) →Tasks: Run Taskand pick the task you want to run. TheStart: Server & Sideloadcomposite is convenient for the full flow.
Example (PowerShell) — install all npm deps then start the full flow manually:
# install all npm deps (runs two installs in parallel via the composite task)
npm --prefix .\Blazor.Word.AddIn install
npm --prefix .\Blazor.Word.AddIn.Client install
# start server (runs in dedicated terminal)
dotnet run --project .\Blazor.Word.AddIn\Blazor.Word.AddIn.csproj
# sideload (run in another dedicated terminal after server is ready)
npm --prefix .\Blazor.Word.AddIn run start-localCross-platform note:
- The examples use PowerShell for Windows. On macOS/Linux use equivalent POSIX shell commands (replace backslashes with forward slashes). Sideload behavior and Office client interaction differ by platform; consult Microsoft documentation for platform specifics.
Troubleshooting
-
Port already in use:
- Check which process is using the default port (7215) and stop it if safe.
netstat -ano | Select-String 7215 Stop-Process -Id <pid> # if safe to stop
lsof -i :7215 kill <pid>
-
Sideload runs only after server exit (ordering issue):
- Use the provided
Start: Server & Sideloadcomposite task (defined in.vscode/tasks.json) and theSideload & Attach (server)launch compound.Run: Serveris a background task with a problem matcher that detects readiness;Sideload: start-localruns afterwards. Ifstart-localneeds an HTTP endpoint to be responsive, add a wrapper that polls the server before executingnpm run start-local.
- Use the provided
-
Attach prompts to pick a process:
- The attach-based workflow intentionally asks you to pick the running
.NETprocess so the debugger attaches to the already-running server (avoids starting a second server and port conflicts). If you want full automation, consider a helper that writes the PID to a temporary file and a small installed helper command to read it intolaunch.json.
- The attach-based workflow intentionally asks you to pick the running
- Did you experience any problems with the sample? Create an issue and we'll help you out.
- We'd love to get your feedback about this sample. Go to our Office samples survey to give feedback and suggest improvements.
- For general questions about developing Office Add-ins, go to Microsoft Q&A using the office-js-dev tag.
| Solution | Authors |
|---|---|
| Create a Blazor Hybrid Word add-in | Maarten van Stam |
| Version | Date | Comments |
|---|---|---|
| 1.0 | XXXXXXXX XX, 2025 | Work In Progress |
Additional contributions to this sample were made by Rudy Cortembert.
Rudy adopted our earlier Blazor Add-in sample and helped to made it work with the new Blazor Hybrid model.
Copyright(c) Maarten van Stam. All rights reserved.Licensed under the MIT License.
This project has adopted the Microsoft Open Source Code of Conduct. For more information, see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments.
Note: The index.html file contains an image URL that tracks diagnostic data for this sample add-in. Please remove the image tag if you reuse this sample in your own code project.
TO DO: Update the image URL below with the correct telemetry URL.