Node.js WinUI 3 Sample
August 4, 2026 ยท View on GitHub
This sample creates a WinUI 3 Application and Window directly from Node.js.
The Microsoft.UI.Xaml controls are projected into JavaScript by dynwinrt. It
does not use Electron, HTML, a WebView, XAML markup, XAML Islands, or a native
addon specific to the sample.
The window contains a Fluent card layout implemented with Grid, Border,
StackPanel, TextBlock, ComboBox, and Button. Each button invokes a
JavaScript callback that updates JavaScript state and WinUI properties. The
theme picker switches the root element between the system, light, and dark
themes and applies the same selection to the system title bar.
Prerequisites
- Windows 11
- Node.js 20 or later
@microsoft/winappcli1.0 or later@microsoft/dynwinrtand@microsoft/dynwinrt-codegenpreview.15 or later
Run the sample
npm install
npm run restore
npm start
npm run restore downloads the SDK metadata, installs the Windows App SDK
runtime, copies the architecture-specific bootstrap DLL under .winapp\bin, and
generates JavaScript bindings under .winapp\bindings. The app loads the
bindings through the #winapp/bindings package import declared in
package.json.
npm start launches node main.js directly without package identity. The main
thread locates the restored bootstrap DLL and initializes the process-wide
Windows App SDK runtime graph before creating the UI worker.
Architecture
main.js bootstraps Windows App SDK 2.2 once for the process, then creates a
Node worker. The worker:
- Initializes a single-threaded WinRT apartment.
- Starts the WinUI
Applicationdispatcher loop. - Composes the application with a WinUI metadata provider and Fluent resources.
- Creates a
Windowwith a Mica backdrop. - Creates the controls imperatively from generated JavaScript bindings.
- Activates the window and exits the application when it closes.
Constructible WinRT classes use normal JavaScript constructors, such as
new Window(), new StackPanel(), and new SolidColorBrush(color).
Application.start() owns the calling thread until the application exits. The
sample runs it in a worker so the main Node.js event loop remains available.
Windows App SDK bootstrap is process-wide, while WinRT apartment initialization
is thread-local, so roInitialize(0) remains in the UI worker.
Application.create() installs the standard WinUI control templates and theme
resources. In an unpackaged process, dynwinrt resolves the
framework resources.pri from the bootstrapped package graph and supplies it to
WinUI's resource manager. The helper also configures Per-Monitor V2 DPI
awareness, so the associated AppWindow size is converted from view pixels to
physical pixels after the content loads. The sample uses AccentButtonStyle
from those resources and refreshes its card brushes when the active Windows
theme changes.
Regenerate bindings
After changing winapp.jsBindings in package.json, run:
npm run restore
ScrollViewer is included as a binding root because its metadata causes
codegen to emit the IVector_UIElement projection used to append child
controls.
If only the generated output was removed and winapp.yaml has not changed, use:
npm run generate