Windows (WinUI 3)

Tier 2 · Demi-supported

windows-winui is the Windows target. It renders WinUI 3 controls (Microsoft.UI.Xaml, from the Windows App SDK 2.5.1) in a Win32 window, hosted through the Windows App SDK’s DesktopWindowXamlSource. day new gives a Windows project this target.

Getting started

You need the Visual Studio C++ Build Tools (for MSVC and the Windows SDK) and the MSVC Rust toolchain. The C++/WinRT shim is compiled by build.rs against the Windows SDK, whose cppwinrt.exe also generates the WinUI projection.

rustup default stable-msvc
cargo install day-cli
day new app my-app --toolkit windows-winui
cd my-app
day launch -p windows-winui

The app’s Cargo.toml carries a winui = ["day/winui"] feature, which the day new template adds.

Development builds (day build, day launch) run framework-dependent, so they need the Windows App Runtime 2.5.1 or newer installed (the Microsoft.WindowsAppRuntime.2 framework package), from Microsoft’s Windows App SDK downloads. If it is missing, the app offers that download page at start-up. day doctor --toolkit winui checks the MSVC toolchain and the runtime.

There is no NuGet or Visual Studio project. On first use the build downloads the Windows App SDK’s NuGet packages itself (about 270 MB, with the in-box curl and tar) into %LOCALAPPDATA%\day\winappsdk. DAY_WINAPPSDK points the build at an already laid-out copy for an offline machine; DAY_WINAPPSDK_CACHE moves the cache.

A Windows machine can also build windows-qt and windows-gtk for development (Tier 4); that runs the same codebase against three desktop toolkits. Those need MSYS2 and a GNU Rust toolchain alongside your MSVC default; Qt and GTK on a Windows host has the recipe.

Packing

day pack -p windows-winui     # .msix plus an NSIS -setup.exe

This writes <app>-windows-winui.msix and <app>-windows-winui-setup.exe. The installer needs NSIS (makensis, e.g. choco install nsis).

A packed app is self-contained: the Windows App SDK runtime DLLs, a merged resources.pri, and a registration-free WinRT manifest travel inside the .msix and the installer, so users install nothing extra. They need Windows 10 version 1809 or later (Windows 11 recommended). Only day pack links this way; day build and day launch stay framework-dependent.

The NSIS installer is per-user: it runs without elevation, adds a normal Add/Remove Programs entry, and offers a silent /S mode for managed deployment. The Microsoft Store rules that day store applies ([microsoft-store] in store-rules.toml) cover this target.

Caveats

  • Fewer applications have shipped on it than on the Apple, Linux, and Android targets. Day-Showcase’s full UI walkthrough passes on it, but no large app ships on it yet.
  • The web view needs the Microsoft Edge WebView2 Runtime, which ships with Windows 11 and current Windows 10. Day uses WinUI 3’s own WebView2 control.
  • picker().segmented() is a horizontal row of radio buttons, since XAML has no native segmented control.
  • The inline time picker falls back to a flyout, because XAML has no inline clock.
  • Text-area read-only and spell-check are native (TextBox.IsReadOnly / IsSpellCheckEnabled). .selectable(false) is emulated, because TextBox has no selection-enable property: the shim collapses each selection as it is reported and suppresses the context menu.
  • Lottie plays through lottie-web in the web view. Map has no XAML arm and renders its placeholder. cover() presents as a topmost window-sized child (no transition, programmatic dismissal only).
  • Radial gradients in a canvas are synthesized into a bitmap brush, a path the shim shares with system XAML, which has no RadialGradientBrush.
  • Screenshots read the window’s real pixels, frame included, through Windows.Graphics.Capture, so they show web view and video content and work while the window is covered.
  • dayscript gates: a step gated on the XAML backend (only_on: [xaml], skip_on: [windows-xaml]) applies to windows-winui too, since it is that backend; winui / windows-winui single out the WinUI build.

Native pieces

A native piece’s XAML half serves both XAML targets: a winui feature that implies the piece’s xaml feature and turns on day-xaml-sys/winui, with "winui" in [package.metadata.day.piece] backends. Its build.rs uses day_toolchain::winappsdk::shim_includes(&cppwinrt) and defines DAY_WINUI when day_toolchain::winappsdk::shim_is_winui(), and the shim switches its includes and namespace on DAY_WINUI. day new piece --toolkits winui scaffolds this; the native piece tutorial walks through it.

Moving from windows-xaml

A project on the deprecated windows-xaml target moves with:

day project add-target windows-winui

then drops windows-xaml from Day.toml. The Rust code needs no changes, since it is the same backend. Development machines need the Windows App Runtime (see Getting started); users of a packed app need nothing extra.

What each piece becomes

The generated coverage matrix, checked in CI, covers every backend; this table adds links and notes.

Day pieceWinUI 3 control (Microsoft.UI.Xaml.Controls)
column / row / nav_stack / sectionCanvas (Day positions children absolutely)
labelTextBlock
buttonButton (AccentButtonStyle when prominent)
toggleToggleSwitch
sliderSlider
text_fieldTextBox
text_areaTextBox with AcceptsReturn
picker().menu()ComboBox
picker().segmented() / .inline()RadioButtons in a horizontal / vertical stack
progress(f)ProgressBar
spinner()ProgressRing
dividerBorder, 1px, themed stroke
scrollScrollViewer
listScrollViewer with Day-side cell pooling
nav (split and stack)NavigationView
nav_menuNavigationViewItems, or a ListView standalone
tabsPivot
imageImage
vectora Path in a scaling Viewbox (XAML geometry); an Image of the raster cache PNG for art outside the convertible subset
canvasCanvas with a Path per shape
dialogs / alerts / promptsContentDialog
file dialogsFileOpenPicker / FileSavePicker
menu barMenuBar
context menusMenuFlyout
external activity()ProgressRing
external combobox()editable ComboBox
external search_field()AutoSuggestBox
external date_picker()CalendarDatePicker, or CalendarView inline
external time_picker()TimePicker
external media()MediaPlayerElement
external webview()WebView2

Text measurement is XAML’s measure pass (Measure → DesiredSize), with a re-measure after forcing layout when a templated control reports zero before the first async layout pass.

Qt and GTK on a Windows host

windows-winui is the target you ship on Windows. GTK and Qt are portable, so the same machine can also run windows-qt and windows-gtk, to check a change against three desktop toolkits before CI or to use one toolkit across Linux and Windows. Both are development combos (Tier 4): day pack refuses them (bundling a toolkit into a Windows installer is deferred), and windows-gtk has no accessibility tree.

Each needs two things: the toolkit’s development libraries from MSYS2, and a second Rust toolchain whose ABI matches them. MSYS2 ships GNU-format import libraries (libgtk-4.dll.a, libQt6Widgets.dll.a) which MSVC’s link.exe cannot read, so the *-pc-windows-msvc toolchain, the correct one for windows-winui, cannot link either of these targets. Install the GNU toolchain alongside your default and select it per shell; don’t rustup default it away from MSVC.

Which MSYS2 environment and toolchain you want depends on the CPU:

Host CPUMSYS2 environmentPackage prefixRust toolchain
x86-64MINGW64 — C:\msys64\mingw64mingw-w64-x86_64-stable-x86_64-pc-windows-gnu
ARM64CLANGARM64 — C:\msys64\clangarm64mingw-w64-clang-aarch64-stable-aarch64-pc-windows-gnullvm

Install the libraries

winget install MSYS2.MSYS2

Then, from the MSYS2 shell, install a compiler, pkgconf, and whichever toolkits you want. The ARM64 package names are shown; on x86-64 swap the prefix and use mingw-w64-x86_64-gcc in place of the clang/lld pair.

pacman -S --needed \
  mingw-w64-clang-aarch64-clang mingw-w64-clang-aarch64-lld \
  mingw-w64-clang-aarch64-pkgconf \
  mingw-w64-clang-aarch64-qt6-base \
  mingw-w64-clang-aarch64-gtk4 mingw-w64-clang-aarch64-libadwaita

Drop the qt6-base line, or the gtk4/libadwaita line, if you only want one of the two. day doctor and the toolkit build scripts probe through pkgconf, and the compiler both links the final binary and builds Qt’s small C++ shim.

Add the Rust toolchain

rustup toolchain install stable-aarch64-pc-windows-gnullvm   # x86-64: stable-x86_64-pc-windows-gnu

Build and run

Every day command for these two targets wants the MSYS2 bin directory on PATH and that toolchain selected. PATH matters twice: the build resolves pkg-config and the compiler through it, and the app loads the GTK/Qt DLLs through it at run time.

$env:PATH = "C:\msys64\clangarm64\bin;$env:PATH"
$env:RUSTUP_TOOLCHAIN = "stable-aarch64-pc-windows-gnullvm"

day doctor --toolkit qt          # and --toolkit gtk
day launch -p windows-qt
day launch -p windows-gtk

Setting RUSTUP_TOOLCHAIN per shell is the only switch: a shell without it still builds windows-winui against MSVC, which that target needs. day doctor will still warn about flatpak-builder and linuxdeploy; those are Linux packaging tools and don’t apply here.

There is one exception, seen on CI images more than on laptops: if a different MinGW is already on PATH (a standalone C:\mingw64, or the one some CI runners ship), the GNU toolchain will link through that one instead and fail to find MSYS2’s -lQt6Widgets / -lglib-2.0. Putting MSYS2’s bin first, as above, is usually enough; pin it outright if not:

$env:CARGO_TARGET_X86_64_PC_WINDOWS_GNU_LINKER = "C:/msys64/mingw64/bin/gcc.exe"
$env:CC  = "C:/msys64/mingw64/bin/gcc.exe"
$env:CXX = "C:/msys64/mingw64/bin/g++.exe"

The first build compiles the native backend and, for Qt, its C++ shim. Subsequent builds reuse compiled dependencies. Build times depend on the host, toolkit, and changed files.

What to expect

  • Neither toolkit has a web engine on Windows. MSYS2 packages neither Qt 6 WebEngine nor WebKitGTK 6, because both embed a browser engine that doesn’t build under MinGW. So webview() shows its URL-label fallback on windows-qt and renders Day’s placeholder leaf on windows-gtk. Everything else, including the external combobox(), search_field(), date_picker(), time_picker(), media(), and activity() pieces, draws a native widget.
  • Custom bundled fonts don’t reach Pango on windows-gtk, so labels asking for a bundled family fall back to the default face. The app logs each one at startup.
  • Toolchains behave differently under the two linkers. Day registers piece renderers through linkme statics, and MinGW’s GNU ld dead-strips some of them, leaving those pieces as placeholders. The clang/lld toolchain used by CLANGARM64 + gnullvm keeps them: a full sweep of the showcase there reports no dropped renderers beyond the GTK web view, which has no Windows build. If pieces render as placeholders on an x86-64 MinGW build, that linker is the cause; see Platform support.